对具有多个元素的链表进行排序

时间:2021-04-20 18:50:46

标签: c sorting linked-list

我有这个 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)

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

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

2 个答案:

答案 0 :(得分: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;
  }

}

答案 1 :(得分:1)

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

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

我在理解您的排序逻辑时遇到了一些困难。而且,使用 traverse->next->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;
}
相关问题