【问题标题】:Sorting linked list with multiple elements对具有多个元素的链表进行排序
【发布时间】:2021-07-14 23:45:47
【问题描述】:

我有这个 csv 文件:

NAME, NUMBER, ADDRESS, EMAIL
Kevin, +62 812-xxx-xxx, Jln.Anggrek Merah 3, kevin@gmail.com
Adwi, +62 821-xxxx-xxxx, Jln.Ruhui Rahayu, adwi@gmail.com
Wasis, +62 813-xxxx-xxxx, Jln.Pramuka 6 25, wasis@gmail.com
Alief, +62 811-xxxx-xxx, Jln.Padat Karya, alief@gmail.com

这是我的代码:

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

#define MAX 50

typedef struct Contact
{
    char name[MAX];
    char number[MAX];
    char address[MAX];
    char email[MAX];
    struct Contact *next;
} 
Contact;

void create_linkedList(Contact **start, Contact p)
{
    Contact *new = malloc(sizeof(Contact));
    strcpy(new->name, p.name);
    strcpy(new->number, p.number);
    strcpy(new->address, p.address);
    strcpy(new->email, p.email);

    new->next = *start;
    *start = new;
}

void printList(Contact *start)
{
    Contact *cursor = start;
    while (cursor != NULL)
    {
        printf("%s\n", cursor->name);
        cursor = cursor->next;
    }
}

void sorting(Contact *start)
{
    Contact *cursor = start, *traverse = NULL;
    Contact *tmp, *tmp_next;
        
    while (cursor != NULL)
    {
        traverse = cursor;

        while (traverse->next != NULL)
        {
            if (strcasecmp(traverse->name, traverse->next->name) > 0)
            {
                tmp = traverse;
                tmp_next = traverse->next->next;
    
                traverse->next = tmp;

                traverse->next->next = tmp_next;
            }
            traverse = traverse->next;
        }
        printf("Prepare!\n");
        cursor = cursor->next;
    }
}

int main(void)
{
    FILE *file = fopen("contacts.csv", "r");
    if (file == NULL)
        return 1;

    Contact person;
    Contact *start = NULL;

    // Loop inside csv file til' the end of file
    while(fscanf(file, "%[^,], %[^,], %[^,], %[^\n] ", person.name, person.number, person.address, person.email) == 4)
    {   
        # Skip header file from csv
        if (strcmp("NAME", person.name) == 0) 
            continue;
        
        create_linkedList(&start, person);
    }    

    printList(start);

    // Swapped
    sorting(start);

    printList(start);

    return 0;
}

所以,在我成功创建了一个链接列表来连接我的 csv 文件中的每个人数据后,我想按他们的名字对其进行排序,然后打印出来。但是如果你编译我的代码,就会导致分段错误。

在我的sort() 函数中,我尝试更改每个人的node (next)。因为我认为如果我只交换每个元素的值,node (next) 仍然会像以前一样指向同一个人。所以我在想也许我只能交换node (next)

如果它只是对数组中的值进行排序,我可以做到。但是链表对于初学者来说很难。

你能帮帮我吗?也许给我写一些新代码并解释解决方案,如果你们有的话。谢谢!

【问题讨论】:

    标签: c sorting linked-list


    【解决方案1】:

    当你想创建一个链表时,你应该使用一个包含两种类型日期的结构单元格:第一种是你的数据本身(在你的情况下是联系人)另一种是指向列表中下一个单元格的指针(下一个)。使用这种类型的实现,您可以使您的代码更具可读性、模块化和可重用性。

    typedef struct Contact
    {
       char name[MAX];
       char number[MAX];
       char address[MAX];
       char email[MAX];
       struct Contact *next;
    }
    Contact;
    
    typedef struct ContactCell {
       Contact info;
       struct ContactCell* next;
    }
    ContactCell;
    typedef ContactCell* ContactList;
    

    使用上面的函数实现将是:

    void addContactToList(ContactList start, Contact p)
    {
       ContactCell* aux = malloc(sizeof(ContactCell));
       aux->info = p;
    
       aux->next = start;
       start = aux;
    }
    
    void printList(ContactList start)
    {
       ContactList cursor = start;
       while (cursor != NULL)
       {
        printf("%s\n", cursor->info.name);
        cursor = cursor->next;
       }
    }
    

    对于排序,我会在单元格之间交换 info(使用上面的实现),因为这种方法使交换更容易理解,特别是对于像 Contact 这样的数据类型(对使用第三个变量进行交换)。以下版本使用选择排序算法(不是超级高效,但更简单)。

    void sorting(ContactList start)
    {
    
      for (ContactList i= start; i!=NULL; i = i->next)
      {
         ContactList current_min = i;
    
         for (ContactList j=i->next ;j!=NULL; j = j->next)
            if (strcasecmp(current_min->info.name,j->info.name) > 0)
               current_min = j;
    
         //swap using a Contact aux variable
         Contact tmp = i->info;
         i->info = current_min->info;
         current_min->info = tmp;
      }
    
    }
    

    【讨论】:

    • 所以我不需要在我的联系人中添加struct Contact *next;,而是我只能像您的代码一样使用struct Cell 来链接它们?这意味着不需要我的create_linkedList
    • 正是通过这种方式,您将数据结构(由单元格指针表示的列表)和您处理的数据类型(联系人)分开。如果你想更精确,你可以添加一个函数 create_linkedlist 来创建一个初始化为 NULL 的联系人列表(仅用于改进代码中隐藏的信息)
    • 非常感谢!我真的很喜欢你说最好使用单独的结构来创建链表。以前不知道!
    【解决方案2】:

    比起传递双星指针(例如Contact **start),我更喜欢单独的List 结构。这可以[轻松]扩展为双向链表。

    另外,我总是将struct 传递给带有指针的函数。按值传递 [正如您在创建列表时所做的那样] 较慢。而且,在一般情况下,如果struct 很大(例如它有一个元素:int data[10000000];),则会导致堆栈溢出

    我在理解您的排序逻辑时遇到了一些困难。而且,使用traverse-&gt;next-&gt;next 对我来说似乎有问题。我无法确切地说出您的排序算法是基于什么的。我猜它正在尝试进行插入排序[但我很容易出错]。

    我更熟悉在合并阶段从源列表中提取并附加到目标列表的链接列表的合并排序。那会很快(呃),而且它可以很好地适应链表。

    但是,我并没有把你的代码弄得那么远,而是从中调整了一些逻辑来创建一个选择排序 [我认为]。

    不管怎样,重构后的代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX 50
    
    typedef struct Contact {
        char name[MAX];
        char number[MAX];
        char address[MAX];
        char email[MAX];
        struct Contact *next;
    } Contact;
    
    typedef struct {
        Contact *head;
    } List;
    
    void
    create_linkedList(List *list, Contact *p)
    {
        Contact *new = malloc(sizeof(Contact));
    
        strcpy(new->name, p->name);
        strcpy(new->number, p->number);
        strcpy(new->address, p->address);
        strcpy(new->email, p->email);
    
        new->next = list->head;
        list->head = new;
    }
    
    void
    printList(List *list)
    {
        Contact *cursor = list->head;
    
        printf("List:\n");
        while (cursor != NULL) {
            printf("  %s\n", cursor->name);
            cursor = cursor->next;
        }
    }
    
    void
    sorting(List *list)
    {
        Contact *oldhead = list->head;
        Contact *newhead = NULL;
        Contact *newprev = NULL;
    
        while (oldhead != NULL) {
            // lowest element to be selected
            Contact *bestcur = oldhead;
            Contact *bestprev = NULL;
    
            // find the lowest element in remaining list
            Contact *travprev = NULL;
            Contact *travcur = oldhead;
            for (;  travcur != NULL;  travcur = travcur->next) {
                if (strcasecmp(bestcur->name,travcur->name) > 0) {
                    bestcur = travcur;
                    bestprev = travprev;
                }
                travprev = travcur;
            }
    
            // remove selected element from old list
            if (bestprev != NULL)
                bestprev->next = bestcur->next;
            else
                oldhead = bestcur->next;
    
            bestcur->next = NULL;
    
            // append to new list
            if (newprev != NULL)
                newprev->next = bestcur;
            else
                newhead = bestcur;
            newprev = bestcur;
        }
    
        list->head = newhead;
    }
    
    int
    main(void)
    {
        FILE *file = fopen("contacts.csv", "r");
    
        if (file == NULL)
            return 1;
    
        Contact person;
        List *list = calloc(1,sizeof(*list));
    
        // Loop inside csv file til' the end of file
        while (fscanf(file, "%[^,], %[^,], %[^,], %[^\n] ",
            person.name, person.number, person.address, person.email) == 4) {
            // Skip header file from csv
            if (strcmp("NAME", person.name) == 0)
                continue;
    
            create_linkedList(list, &person);
        }
    
        printList(list);
    
        // Swapped
        sorting(list);
    
        printList(list);
    
        return 0;
    }
    

    【讨论】:

    • 非常感谢,这很有帮助!
    猜你喜欢
    • 2023-04-03
    • 2017-08-25
    • 1970-01-01
    • 2018-04-07
    • 2021-08-06
    • 2012-04-15
    • 2013-11-07
    • 2013-08-24
    • 2016-04-11
    相关资源
    最近更新 更多