簡體   English   中英

C語言中的這種排序算法有什么問題?

[英]What is wrong with this sorting algorithm in C?

我正在嘗試一個必須按字母順序排列5000個名字的列表的問題(這些名字存儲在文本文件"names.txt" )。 從下面的代碼可以看出,我創建了一個二維數組names[n][m]用於存儲名稱。

對於每個名稱,我將其與所有其他名稱按字母順序進行比較。 只要第i個名字按字母順序大於另一個,存儲在其數組元素rank[i]按字母順序排列的排名就會增加。 例如,當將"Mary""Denise"進行比較時,瑪麗的排名將增加1,因為它的字母順序比丹妮絲大。 所有等級從1開始。

當用問題中提供的示例進行測試時,這似乎是成功的,因為它是成功的。 但是,我得到的最終答案是錯誤的。 更重要的是,我發現幾個名稱共享相同的排名(即,我檢查並發現"Columbus""Colt"都具有相同的排名)。 我不確定我的算法為何存在缺陷或在何處存在缺陷,因為在邏輯上對我來說聽起來很合理(?)。 我嘗試通過添加一些注釋來使代碼更具可讀性,如果有人可以向我解釋我的錯誤,我將不勝感激。 我只編碼了幾天,所以如果我犯了任何菜鳥錯誤,請原諒我。 謝謝你的時間!

鏈接到問題: https : //projecteuler.net/problem=22

編輯:代碼被略微截斷了(我省略了最后一步,我只是將所有分數加在一起)。 但是我所說的錯誤僅與提供的代碼有關。 謝謝!

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

int main() {
    FILE *fp;
    int i, j;
    int a = 0;
    int b = 0;
    fp = fopen("names.txt", "r");
    char names[5200][30] = { 0 };
    int rank[5200] = { 0 }; //Rank corresponds to their alphabetical positions
    unsigned long long score[5200] = { 0 };
    unsigned long long sum = 0;
    for (i = 0; i < 5200; i++) {
        (rank[i])++;  //All the rankings start from 1.
    }
    for (i = 0; !feof(fp); i++) {
        fscanf(fp, "\"%[A-Z]\",", &names[i]); //Scanning and storing the names from the file into the array.
    }

    for (i = 0; i < 5200; i++) {
        for (j = 0; j < 5200; j++) {
            if (i != j && names[i][0] != 0 && names[j][0] != 0) {
                while (names[i][a] == names[j][a]) {  //If the ith word and jth word have the same letter, then increment a (which advances to the next letter).
                    a++;
                }
                if (names[i][a] > names[j][a]) { 
                    (rank[i])++; //If the ith word has a larger letter than the jth word, there will be an increase in its rank.
                } else
                if (names[j][a] == 0 && names[i][a] != 0) { 
                    (rank[i])++; //If the jth word is shorter than the ith word, then i also increases its rank.
                }
            }
            a = 0;
        }
        for (a = 0; a < 30; a++) {
            if (names[i][a] != 0 && names[i][0] != 0) {
                score[i] += (names[i][a] - 64); //Sum up the alphabetical value (as per the question) for each name.
            }
        }
        score[i] = (rank[i]) * (score[i]);
    }

您的算法有效,但存在一些實現問題:

  • for (i = 0; !feof(fp); i++) {的測試不正確。 fscanf()可能無法在文件結尾之前轉換文件內容,從而導致無限循環。 相反,您應該測試fscanf()是否成功返回1
  • 您應該計算讀入數組的單詞數並將循環限制在此范圍內。
  • 您不應假定文件中的名稱沒有重復。 如果ij的內容相同, while (names[i][a] == names[j][a]) { a++ }循環將具有未定義的行為。 確實,使用strcmp()比較名稱更簡單,更安全。
  • 無需保留所有名稱的等級和分數,您可以在外循環內即時計算總和。 這也節省了初始化代碼。

這是一個經過糾正和簡化的版本:

#include <stdio.h>
#include <string.h>

int main() {
    char names[5200][30];
    FILE *fp;
    int i, j, n, a, rank, score;
    unsigned long long sum = 0;

    fp = fopen("p022_names.txt", "r");
    if (fp == NULL)
        return 1;

    // Scan and store the names from the file into the array.
    for (n = 0; n < 5200; n++) {
        if (fscanf(fp, "\"%29[A-Z]\",", names[n]) != 1)
            break;
    }
    fclose(fp);

    // n first names read from file.
    for (i = 0; i < n; i++) {
        rank = 1;
        for (j = 0; j < n; j++) {
            if (strcmp(names[i], names[j]) > 0)
                rank++;
        }
        score = 0;
        for (a = 0; names[i][a] != '\0'; a++) {
            // Sum up the alphabetical value (as per the question) for each name.
            score += names[i][a] - 'A' + 1;
        }
        sum += rank * score;
    }
    printf("Total score of %d names: %lld\n", n, sum);
    return 0;
}

輸出:

Total score of 5163 names: 871198282

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM