代码之家  ›  专栏  ›  技术社区  ›  fgdark

如何通过在C中使用插入排序为每行提供有序索引来对文件中的字符串进行排序

  •  0
  • fgdark  · 技术社区  · 8 年前

    我在整理这个文件时遇到了问题,无法给每行一个索引。整个要点是提示用户输入索引,以便程序可以返回与索引号对应的程序行。

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    
    void printUnsortedStringFromFile(int amount, char A[]);
    void printSortedStringFromFile(int amount, char A[]);
    //bool binSearchNUM(int amount, int A[amount], int target, int *current);
    
    int main()
    {
    
        FILE* spData = fopen("grades.csv", "r");
        int ch, number_of_lines = 0;
        do
        {
            ch = fgetc(spData);
            if (ch == '\n')
                number_of_lines++;
        } while (ch != EOF);
    
        if (ch != '\n' && number_of_lines != 0)
            number_of_lines++;
    
        fclose(spData);
    
        printf("There are %d lines in file grades.csv . \n", number_of_lines);
        int amount = number_of_lines;
        char A[amount];
        printUnsortedStringFromFile(amount, A);
        printSortedStringFromFile(amount, A);
        return 0;
    }
    
    
    void printUnsortedStringFromFile(int amount, char A[])
    {
        FILE *spData;
        spData = fopen("grades.csv", "r");
        if(spData == NULL)
        {
            fprintf(stderr, "Error opening the file grades.csv.\n");
            exit(1);
        }
    
    
        int ex1;
        int ex2;
        int ex3;
        int StudentNUM;
        char StudentAVG;
    
        printf("+-------+------+------+------+-----+\n");
        printf("|Student|Exam 1|Exam 2|Exam 3|Grade|\n");
        printf("+-------+------+------+------+-----+\n");
        int z = 0;
        while((fgets(A, amount, spData)) != NULL)
        {
            sscanf(A, "%d, %d, %d, %d, %c", &StudentNUM, &ex1, &ex2, &ex3, &StudentAVG);
            printf("| %d|    %d|    %d|    %d|    %c| \n", StudentNUM, ex1, ex2, ex3, StudentAVG);
            z++;
    //prints unsorted correctly
        }
        printf("+-------+------+------+------+-----+\n");
    
        if (fclose(spData) == EOF)
        {
            fprintf(stderr, "Error closing the file grades.csv. \n");
            exit(2);
        }
    }
    void printSortedStringFromFile(int amount, char A[])
    {
        FILE *spData;
        spData = fopen("grades.csv", "r");
        if(spData == NULL)
        {
            fprintf(stderr, "Error opening the file grades.csv.\n");
            exit(1);
        }
      //help needed implementing insertion sort to sort each string as an index here
        {
        int walk;
        int temp;
        for (int cur = 1; cur < amount; cur++)
            {
            bool located = false;
             temp = A[cur], walk = cur-1;
            while (walk >= 0 && !located)
            {
                if (temp < A[walk])
                    {
                    A[walk+1] = A[walk];
                    walk--;
                        }
                        else
                        {
                            located = true;
                        }
            }
                A[walk+1] = temp;
            }
        }
    
    
        int StudentNUM;
        char StudentAVG;
    
        printf("+-----+-------+-----+\n");
        printf("|Index|Student|Grade|\n");
        printf("+-----+-------+-----+\n");
        int z = 0;
        while((fgets(A, amount, spData)) != NULL)
        {
            sscanf(A, "%d, %c", &StudentNUM, &StudentAVG);
            printf("|    %d|    %c| \n", StudentNUM, StudentAVG);
            z++;
    //student ID prints, grade average doesn/t, unsure how to sort these strings into a numbered(index) list
        }
        if (fclose(spData) == EOF)
        {
            fprintf(stderr, "Error closing the file grades.csv. \n");
            exit(2);
        }
    
    }
    /* (correct) example output:
    There are 5 lines in file grades.csv.
    Original:
    +-------+------+------+------+-----+
    |Student|Exam 1|Exam 2|Exam 3|Grade|
    +-------+------+------+------+-----+
    | 535743|    67|    96|    93|    B|
    | 112213|    87|    65|    72|    C|
    | 612778|    59|    58|    97|    C|
    | 151774|    52|   100|    86|    C|
    | 406704|    54|    72|    80|    D|
    +-------+------+------+------+-----+
    Sorted:
    +-----+-------+-----+
    |Index|Student|Grade|
    +-----+-------+-----+
    |    1| 112213|    C|
    |    2| 151774|    C|
    |    3| 406704|    D|
    |    4| 535743|    B|
    |    5| 612778|    C|
    +-----+-------+-----+
    */
    
    2 回复  |  直到 8 年前
        1
  •  0
  •   J. Piquard    8 年前

    源代码中的主要问题是字符串 char A[amount]; .

    main() 函数变量 A

    在您的示例中, number_of_lines = 5 方法 A[amount] = A[5] 是 只能存储4个字符的字符串+空终止符。

    printf("There are %d lines in file grades.csv . \n", number_of_lines);
    int amount = number_of_lines;
    char A[amount];
    printUnsortedStringFromFile(amount, A);
    printSortedStringFromFile(amount, A);
    

    printUnsortedStringFromFile() printSortedStringFromFile() 函数具有相同的变量 A. 用作加载和读取一行的缓冲区。

    在您的示例中,第一行是“等级”。csv'长度超过4个字符 并且在调用之前被截断 sscanf() .

    while((fgets(A, amount, spData)) != NULL)
    {
        sscanf(A, "%d, %d, %d, %d, %c", &StudentNUM, &ex1, &ex2, &ex3, &StudentAVG);
    

    解决方案可以是使用本地 char sTmp[80] 对于 fgets() sscanf() 并使用 A[amount] 仅用于指数化。


    答案是第二部分。

    源代码中的第二个问题是,为了通过插入排序升序学生id排序记录,建议的索引不仅需要存储索引,还需要存储每个记录的内容。我建议使用定义结构如下:

    struct gradesRecord {
        int iIndex;       // index on the file
        int iStudentNUM;  // 'Student' field
        int iExamVAL[3];  // 'Exam 1'..'Exam 3' fields
        char cStudentAVG; // 'Grade' field
    };
    

    然后将 A[] char struct gradesRecord main() ):

    int amount = number_of_lines;
    struct gradesRecord A[amount];
    printUnsortedStringFromFile(amount, A);
    printSortedStringFromFile(amount, A);
    

    printUnsortedStringFromFile() 函数,数组 A[] 直接用于读取循环:

    返回值 sscanf() 为了检测丢失的参数(请参阅 nArg 变量以及如何检查波纹管)。

    char sLine[81]; // local string to read one row
    int z = 0; // storage index
    int nArg;
    
    while((fgets(sLine, 80, spData)) != NULL)
    {
        nArg = sscanf(sLine, "%d, %d, %d, %d, %c",
            &(A[z].iStudentNUM), &(A[z].iExamVAL[0]),
            &(A[z].iExamVAL[1]), &(A[z].iExamVAL[2]),
            &(A[z].cStudentAVG));
    
        if (nArg != 5) {
            // the input line is not correct !!!
            // manage that error.
        }
    
        printf("|%7d| %5d| %5d| %5d|    %c| \n", A[z].iStudentNUM,
            A[z].iExamVAL[0], A[z].iExamVAL[1], A[z].iExamVAL[2],
            A[z].cStudentAVG);
        z++; // next row
    

    然后在 printSortedStringFromFile() 函数,数组 A[] 用于在读取循环中存储、排序,然后在第二个循环中显示:

    第一个循环,所有行的读取和选择排序:

    char sLine[81];
    int iLine = 0, iRow;
    struct gradesRecord grRow,grTmp;
    
    while((fgets(sLine, 80, spData)) != NULL)
    {
        // extract one Row and store it into grRow
        sscanf(sLine, "%d, %d, %d, %d, %c",
            &(grRow.iStudentNUM), &(grRow.iExamVAL[0]),
            &(grRow.iExamVAL[1]), &(grRow.iExamVAL[2]),
            &(grRow.cStudentAVG));
        // keep the line index of that row
        grRow.iIndex = iLine;
        // search loop = insertion sort algorithm
        for (iRow=0;iRow<iLine;iRow++) {
            //  detect if new student is before the store one
            if (grRow.iStudentNUM < A[iRow].iStudentNUM) {
                // exchange both stuident records through grTmp
                memcpy(&grTmp,&(A[iRow]),sizeof(struct gradesRecord));
                memcpy(&(A[iRow]),&grRow,sizeof(struct gradesRecord));
                memcpy(&grRow,&grTmp,sizeof(struct gradesRecord));
            }
        }
        // store the biggest student at the end
        memcpy(&(A[iLine]),&grRow,sizeof(struct gradesRecord));
        iLine++;
    }
    

    第二个循环,显示排序表:

    while (z < amount)
    {
        StudentNUM = A[z].iStudentNUM;
        StudentAVG = A[z].cStudentAVG;
        index = A[z].iIndex;
        printf("| %4d|%7d|    %c| \n", index, StudentNUM, StudentAVG);
        z++;
    }
    
        2
  •  0
  •   J. Piquard    8 年前

    为了综合第一个答案中描述的所有修改,我在这里添加完整的源代码如下:

    1-功能 main() struct gradesRecord :

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    
    struct gradesRecord {
        int iIndex;       // index on the file
        int iStudentNUM;  // 'Student' field
        int iExamVAL[3];  // 'Exam 1'..'Exam 3' fields
        char cStudentAVG; // 'Grade' field
    };
    
    void printUnsortedStringFromFile(int amount, struct gradesRecord A[]);
    void printSortedStringFromFile(int amount, struct gradesRecord A[]);
    
    int main()
    {
    
        FILE* spData = fopen("grades.csv", "r");
        int ch, number_of_lines = 0;
        do
        {
            ch = fgetc(spData);
            if (ch == '\n')
                number_of_lines++;
        } while (ch != EOF);
    
        if (ch != '\n' && number_of_lines != 0)
            number_of_lines++;
    
        fclose(spData);
    
        printf("There are %d lines in file grades.csv . \n", number_of_lines);
        int amount = number_of_lines;
        struct gradesRecord A[amount];
        printUnsortedStringFromFile(amount, A);
        printSortedStringFromFile(amount, A);
        return 0;
    }
    

    2-功能 printUnsortedStringFromFile() :

    void printUnsortedStringFromFile(int amount, struct gradesRecord A[])
    {
        FILE *spData;
        spData = fopen("grades.csv", "r");
        if(spData == NULL)
        {
            fprintf(stderr, "Error opening the file grades.csv.\n");
            exit(1);
        }
    
        printf("+-------+------+------+------+-----+\n");
        printf("|Student|Exam 1|Exam 2|Exam 3|Grade|\n");
        printf("+-------+------+------+------+-----+\n");
        char sLine[81]; // local string to read one row
        int z = 0;
        while((fgets(sLine, 80, spData)) != NULL)
        {
            sscanf(sLine, "%d, %d, %d, %d, %c",
                &(A[z].iStudentNUM), &(A[z].iExamVAL[0]),
                &(A[z].iExamVAL[1]), &(A[z].iExamVAL[2]),
                &(A[z].cStudentAVG));
    
            printf("|%7d| %5d| %5d| %5d|    %c| \n", A[z].iStudentNUM,
                A[z].iExamVAL[0], A[z].iExamVAL[1], A[z].iExamVAL[2],
                A[z].cStudentAVG);
            z++;
        }
        printf("+-------+------+------+------+-----+\n");
    
        if (fclose(spData) == EOF)
        {
            fprintf(stderr, "Error closing the file grades.csv. \n");
            exit(2);
        }
    }
    

    3-和函数 printSortedStringFromFile() :

    void printSortedStringFromFile(int amount, struct gradesRecord A[])
    {
        FILE *spData;
        spData = fopen("grades.csv", "r");
        if(spData == NULL)
        {
            fprintf(stderr, "Error opening the file grades.csv.\n");
            exit(1);
        }
    
        char sLine[81];
        int iLine = 0, iRow;
        struct gradesRecord grRow,grTmp;
    
        while((fgets(sLine, 80, spData)) != NULL)
        {
            // extract one Row and store it into grRow
            sscanf(sLine, "%d, %d, %d, %d, %c",
                &(grRow.iStudentNUM), &(grRow.iExamVAL[0]),
                &(grRow.iExamVAL[1]), &(grRow.iExamVAL[2]),
                &(grRow.cStudentAVG));
            // keep the line index of that row
            grRow.iIndex = iLine;
            // search loop = insertion sort algorithm
            for (iRow=0;iRow<iLine;iRow++) {
                //  detect if new student is before the store one
                if (grRow.iStudentNUM < A[iRow].iStudentNUM) {
                    // exchange both stuident records through grTmp
                    memcpy(&grTmp,&(A[iRow]),sizeof(struct gradesRecord));
                    memcpy(&(A[iRow]),&grRow,sizeof(struct gradesRecord));
                    memcpy(&grRow,&grTmp,sizeof(struct gradesRecord));
                }
            }
            // store the biggest student at the end
            memcpy(&(A[iLine]),&grRow,sizeof(struct gradesRecord));
            iLine++;
        }
    
        int StudentNUM;
        char StudentAVG;
    
        printf("+-----+-------+-----+\n");
        printf("|Index|Student|Grade|\n");
        printf("+-----+-------+-----+\n");
        int z = 0;
        int index;
        while (z < amount)
        {
            StudentNUM = A[z].iStudentNUM; // access to sorted array
            StudentAVG = A[z].cStudentAVG;
            index = A[z].iIndex;
            printf("| %4d|%7d|    %c| \n", index, StudentNUM, StudentAVG);
            z++;
        }
        if (fclose(spData) == EOF)
        {
            fprintf(stderr, "Error closing the file grades.csv. \n");
            exit(2);
        }
    
    }