【问题标题】:Sorting a linked list alphabetically in C在C中按字母顺序对链表进行排序
【发布时间】:2015-12-08 15:20:32
【问题描述】:

我编写了以下程序,以地址格式存储来自文件的输入,并按存储在节点中的城市名称的字母顺序对链表进行排序。示例输入如下:

Titus \n
Kollman \n
1522 Foggy Grove Loop \n
Wildcat NC 27507 \n
(252) 644-5477 \n

...等

我的代码当前正确地创建了所有条目的未排序链表,并且我编写了一个排序函数来按字母顺序对列表进行排序。当我尝试对列表进行排序时,我的代码只是连续运行而没有输出(卡住),我找不到我的排序算法有什么问题。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* make node structure to store the data in */
struct entry {
    char fname[64];
    char lname[64];
    char city[64];
    char address[64];
    char cityandstate[64];
    char numb[64];
    struct entry* next;
};

/* function to add entry that will be used in sort*/
void addEntryForSort(struct entry* list, struct entry* x){
    struct entry* newNode = (struct entry*) malloc(sizeof(struct entry));
    memcpy(newNode,x,sizeof(struct entry));
    newNode->next = NULL;
    while (list->next != NULL){
        list = list->next;
    }
    list->next = newNode;
}
/*function to find the minimum (alpha)of a linked list */
struct entry* findMin(struct entry* begin){
    struct entry* curr = begin;
    struct entry* min = curr;
    curr = curr->next;
    while (curr != NULL){
        if (strcmp(curr->city,min->city) < 0){
            min = curr;
        }
        else if (strcmp(curr->city,min->city))
            curr = curr->next;
    }
    return min;
}

/*sort function (attempt)*/
struct entry* sort(struct entry* top){
    struct entry* sorted = (struct entry*) malloc(sizeof(struct entry));
    struct entry* min = findMin(top);
    struct entry* curr = top;
    while (curr->next != NULL){
        if (top == min){
            addEntryForSort(sorted,min);
            top = top->next;
            min = findMin(top);
            curr = top;
        }
        if (curr->next == min){
            addEntryForSort(sorted,min);
            curr->next = curr->next->next;
            min = findMin(top);
            curr = top;
        }
        else {
            curr = curr->next;
        }
    }
    addEntryForSort(sorted,top);
    addEntryForSort(sorted,curr);
    return sorted;
}


int main() {

    struct entry* head = (struct entry*) malloc(sizeof(struct entry));
    char x[64];

    fgets(x,64,stdin);
    strcpy(head->fname,x);
    strtok(head->fname,"\n");

    fgets(x,64,stdin);
    strcpy(head->lname,x);
    strtok(head->lname,"\n");

    fgets(x,64,stdin);
    strcpy(head->address,x);
    strtok(head->address,"\n");

    fgets(x,64,stdin);
    strcpy(head->cityandstate,x);
    strtok(head->cityandstate,"\n");
    strncpy(head->city,head->cityandstate,strlen(head->cityandstate)-10);

    fgets(x,64,stdin);
    strcpy(head->numb,x);
    strtok(head->numb,"\n");
    fgets(x,64,stdin);

    int line = 7;

    struct entry* curr = (struct entry*) malloc(sizeof(struct entry));
    struct entry* prev = head;
    head->next = curr;

    while (fgets(x,64,stdin) != NULL) {
        switch (line % 6){
            case 1:
                strcpy(curr->fname,x);
                strtok(curr->fname,"\n");
                break;
            case 2:
                strcpy(curr->lname,x);
                strtok(curr->lname,"\n");
                break;
            case 3:
                strcpy(curr->address,x);
                strtok(curr->address,"\n");
                break;
            case 4:
                strcpy(curr->cityandstate,x);
                strtok(curr->cityandstate,"\n");
                strncpy(curr->city,curr->cityandstate,strlen(curr->cityandstate)-10);
                if (strcmp(curr->city,"Old Roach MO 6") == 0){
                    strcpy(curr->city,"Old Roach");
                }
                break;
            case 5:
                strcpy(curr->numb,x);
                strtok(curr->numb,"\n");
                break;
            case 0:
                curr->next = (struct entry*) malloc(sizeof(struct entry));
                prev = curr;
                curr = curr->next;
                break;              
        }
        line++;
    }

    curr=sort(head);
    while (curr!= NULL){
        printf("%s %s %s\n",curr->fname,curr->lname,curr->city);
        curr = curr->next;
    }
}

【问题讨论】:

  • 您是否尝试过查看代码中发生了什么?您可以使用调试器逐步完成它,或者使用老式的方法在不同的地方插入 printf 语句。从您所写的内容来看,您现在所知道的只是它“卡住了”。所有的调试都是为了越来越缩小范围,最后找到错误。例如,您的程序到底卡在了哪里?可能在一个循环中,但哪个循环?
  • 不要从malloc返回。

标签: c list sorting


【解决方案1】:

这段代码有很多问题。

首先,你永远不会初始化你的结构,malloc 也不应该这样做,所以next 成员可能不为空,从而使以下所有代码都失败。你应该写:

struct entry* head = (struct entry*) malloc(sizeof(struct entry));
head->next = NULL;  /* ensure next is correctly initialized */

接下来:

struct entry* curr = (struct entry*) malloc(sizeof(struct entry));
curr->next = NULL;  /* ensure next is correctly initialized */

您使用 strncpy 来初始化 city 字段。但是 strncpy 不会添加终止空值,从而使您的字段未终止。你应该写:

strncpy(curr->city,curr->cityandstate,strlen(curr->cityandstate)-10);
curr->city[strlen(curr->cityandstate)-10] = '\0';

(第一次记录与head 相同)。

findMin 中,如果两条记录比较相等,您将停留在那里,因为您没有调用curr = curr-&gt;next。确实应该是:

/*function to find the maximum (alpha)of a linked list */
struct entry* findMax(struct entry* curr){
    struct entry* min = curr;
    while (curr != NULL){
        if (strcmp(curr->city,min->city) > 0){
            min = curr;
        }
        curr = curr->next;
    }
    return min;
}

我得到的是最大值而不是最小值,因为用简单的冒泡排序对单链表进行排序,最简单的方法是原地排序,从列表中取出最大的元素并将其放在首位结果列表。此外,这避免了分配新结构,因为如果您不想泄漏内存,您必须释放每个分配的块。 sort 函数可以变成:

/*sort function (attempt)*/
struct entry* sort(struct entry* top){
    struct entry* sorted = NULL;
    while (top != NULL) {
        struct entry* max = findMax(top);
        if (max == top) { /* if max is first, simply increment top */
            top = top->next;
        }
        else { /* else make prev->next = max->next to remove max from the list */
            struct entry *curr = top;
            while (curr->next != min) curr = curr->next;
            curr->next = min->next;
        }
        /* and put current max in first place of the sorted list */
        max->next = sorted;
        sorted = max;
    }
    return sorted;
}

最后,你应该释放所有分配的内存块,方法是在 main 的末尾添加:

/* free all elements of the linked list */
while(head != NULL) {
    curr = head->next;
    free(head);
    head = curr;
}
return 0; /* never return random value to environment */

但如果你想做严肃的编程,你也应该:

  • 测试所有输入函数,此处fgets 不应返回 NULL,缓冲区应以\n 作为最后一个字符
  • 控制输入字段的格式(电话号码、城市和邮政编码) - 特别是,如果您在末尾没有正确的空格计数,则依赖于从字符串末尾开始的多个位置将会失败一行
  • 将读取记录的代码放入函数中,因为您使用它两次,并且应该学习遵循 DRY(不要重复自己)最佳使用实践

【讨论】:

    猜你喜欢
    • 2019-05-14
    • 2014-06-04
    • 2016-10-12
    • 2013-05-02
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    相关资源
    最近更新 更多