Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C中对具有多个元素的双链表进行排序?_C_Sorting_Linked List_Bubble Sort_Doubly Linked List - Fatal编程技术网

如何在C中对具有多个元素的双链表进行排序?

如何在C中对具有多个元素的双链表进行排序?,c,sorting,linked-list,bubble-sort,doubly-linked-list,C,Sorting,Linked List,Bubble Sort,Doubly Linked List,我需要对具有多个元素的双链接列表进行排序,我的结构如下: typedef struct node { int code; char name[40]; char job[40]; int salary; struct nodo *next; struct nodo *prev; } node; 具体来说,我必须创建一个函数,该函数接收一个*头,并按工资从低到高对元素进行排序,例如 node1->salary = 1000; node2->sala

我需要对具有多个元素的双链接列表进行排序,我的结构如下:

typedef struct node {
   int code;
   char name[40];
   char job[40];
   int salary;
   struct nodo *next;
   struct nodo *prev;
} node;
具体来说,我必须创建一个函数,该函数接收一个*头,并按工资从低到高对元素进行排序,例如

node1->salary = 1000;
node2->salary = 500;
node3->salary = 1500;
函数必须排序,以便将顺序设置为node2、node1、node3。以下是我迄今为止所做的尝试:

void sort(node *head) 
{ 
    int swapped, i; 
    node *ptr1; 
    node *lptr = NULL; 

    if (top == NULL) 
        return; 

    do
    { 
        swapped = 0; 
        ptr1 = head; 

        while (head->next != lptr) 
        { 
            if (ptr1->salary > ptr1->next->salary) 
            {  
                // This part actually only changes the positions of the salary
                // I need to change the position of all the elements
                node *temp;
                temp->salary= ptr1->salary;
                ptr1->salary= ptr1->next->salary;
                ptr1->next->salary= temp->salary;
                swapped = 1; 
            } 
            ptr1 = ptr1->next; 
        } 
        lptr = ptr1; 
    } 
    while (swapped); 
} 

下面是一个示例,按asc和desc顺序进行排序

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

typedef struct node {
   int code;
   char name[40];
   char job[40];
   int salary;
   struct node *next;
   struct node *prev;
} node;

void swapNodes(node *a, node *b) {
  node tmp = *a;
  a->code = b->code;
  strcpy(a->name, b->name);
  strcpy(a->job, b->job);
  a->salary = b->salary;
  b->code = tmp.code;
  strcpy(b->name, tmp.name);
  strcpy(b->job, tmp.job);
  b->salary = tmp.salary;
}

//////////////////////////////////////////////////////////////////////////////////////
// \brief  Sort the linked list in ascending or descending order
// \param  head        The head node of the list
//
// \param  isReversed  Whether to sort in asc or desc, false for asc and true for desc
//////////////////////////////////////////////////////////////////////////////////////
void sort(node *head, bool isReversed) {
  // store the current and the previous nodes
  node *currentNode, *previousNode;
  // store if there still a difference in the list means that we have some nodes not sorted
  bool difference;
  loopAgain:
    // looping again and assuming no more difference
    difference = false;
    currentNode = previousNode = head;
    // loop over the list
    while(currentNode != NULL) {
      currentNode = currentNode->next;
      // check for salary if the current salary is less than the previous and in ascending mode
      // then swap the nodes and the opposite in descending mode
      if(currentNode != NULL && (isReversed ? previousNode->salary < currentNode->salary :
          previousNode->salary > currentNode->salary)) {
        swapNodes(previousNode, currentNode);
        difference = true;
      }
      previousNode = currentNode;
    }
  // go to loop again since there still maybe no sorted nodes yet
  if(difference) {
    goto loopAgain;
  }
}

int main() {
  node n1 = {0, "a", "-", 3500, NULL, NULL},
    n2 = {0, "b", "-", 500, NULL, &n1},
    n3 = {0, "c", "-", 1500, NULL, &n2};
  n1.next = &n2;
  n2.next = &n3;
  printf("Before sort:\n%s)%d\n%s)%d\n%s)%d\n", n1.name, n1.salary, n2.name, n2.salary, n3.name, n3.salary);
  sort(&n1, false);
  printf("After ascending sort:\n%s)%d\n%s)%d\n%s)%d\n", n1.name, n1.salary, n2.name, n2.salary, n3.name, n3.salary);
  sort(&n1, true);
  printf("After descending sort:\n%s)%d\n%s)%d\n%s)%d", n1.name, n1.salary, n2.name, n2.salary, n3.name, n3.salary);
  return 0;
}

下面是一个示例,按asc和desc顺序进行排序

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

typedef struct node {
   int code;
   char name[40];
   char job[40];
   int salary;
   struct node *next;
   struct node *prev;
} node;

void swapNodes(node *a, node *b) {
  node tmp = *a;
  a->code = b->code;
  strcpy(a->name, b->name);
  strcpy(a->job, b->job);
  a->salary = b->salary;
  b->code = tmp.code;
  strcpy(b->name, tmp.name);
  strcpy(b->job, tmp.job);
  b->salary = tmp.salary;
}

//////////////////////////////////////////////////////////////////////////////////////
// \brief  Sort the linked list in ascending or descending order
// \param  head        The head node of the list
//
// \param  isReversed  Whether to sort in asc or desc, false for asc and true for desc
//////////////////////////////////////////////////////////////////////////////////////
void sort(node *head, bool isReversed) {
  // store the current and the previous nodes
  node *currentNode, *previousNode;
  // store if there still a difference in the list means that we have some nodes not sorted
  bool difference;
  loopAgain:
    // looping again and assuming no more difference
    difference = false;
    currentNode = previousNode = head;
    // loop over the list
    while(currentNode != NULL) {
      currentNode = currentNode->next;
      // check for salary if the current salary is less than the previous and in ascending mode
      // then swap the nodes and the opposite in descending mode
      if(currentNode != NULL && (isReversed ? previousNode->salary < currentNode->salary :
          previousNode->salary > currentNode->salary)) {
        swapNodes(previousNode, currentNode);
        difference = true;
      }
      previousNode = currentNode;
    }
  // go to loop again since there still maybe no sorted nodes yet
  if(difference) {
    goto loopAgain;
  }
}

int main() {
  node n1 = {0, "a", "-", 3500, NULL, NULL},
    n2 = {0, "b", "-", 500, NULL, &n1},
    n3 = {0, "c", "-", 1500, NULL, &n2};
  n1.next = &n2;
  n2.next = &n3;
  printf("Before sort:\n%s)%d\n%s)%d\n%s)%d\n", n1.name, n1.salary, n2.name, n2.salary, n3.name, n3.salary);
  sort(&n1, false);
  printf("After ascending sort:\n%s)%d\n%s)%d\n%s)%d\n", n1.name, n1.salary, n2.name, n2.salary, n3.name, n3.salary);
  sort(&n1, true);
  printf("After descending sort:\n%s)%d\n%s)%d\n%s)%d", n1.name, n1.salary, n2.name, n2.salary, n3.name, n3.salary);
  return 0;
}

首先,有一个拼写错误

typedef struct node {
   int code;
   char name[40];
   char job[40];
   int salary;
   struct nodo *next;
          ^^^^
   struct nodo *prev;
          ^^^^
} node;
应该有

typedef struct node {
   int code;
   char name[40];
   char job[40];
   int salary;
   struct node *next;
          ^^^^
   struct node *prev;
          ^^^^ 
} node;
其次,如果要对列表进行排序,则应该对其节点的顺序进行排序,而不是交换节点的数据成员的值。例如,在main中,可以声明指向某个节点的指针。如果要通过交换节点的数据成员的值对列表进行排序,则指针将无效,因为指向的节点的数据成员已更改

第三,应该将除指针next和prev之外的所有数据成员放在一个单独的结构中。在这种情况下,函数声明看起来要简单得多,因为您不需要向函数传递多个初始值设定项,而只需要传递一个结构类型的对象

比如说

typedef struct Person
{
    int  code;
    char name[N];
    char job[N];
    int  salary;
} Person;

typedef struct Node 
{
    Person person;  
    struct Node *prev;
    struct Node *next;
} Node;
typedef struct List
{
    Node *head;
    Node *tail;
} List;
最后,如果处理一个双链接列表,则假定可以在列表的开头和结尾添加新节点。这意味着您应该保留两个指针:一个指向列表的第一个节点,另一个指向列表的最后一个节点。这样做的结果是,您应该声明另外一个结构来描述列表,例如

typedef struct Person
{
    int  code;
    char name[N];
    char job[N];
    int  salary;
} Person;

typedef struct Node 
{
    Person person;  
    struct Node *prev;
    struct Node *next;
} Node;
typedef struct List
{
    Node *head;
    Node *tail;
} List;
现在,当一切准备就绪时,是时候展示如何将冒泡排序方法应用于这样一个列表了

这是一个演示程序

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

enum { N = 40 };

typedef struct Person
{
    int  code;
    char name[N];
    char job[N];
    int  salary;
} Person;

typedef struct Node 
{
    Person person;  
    struct Node *prev;
    struct Node *next;
} Node;

typedef struct List
{
    Node *head;
    Node *tail;
} List;

int push_back( List *list, const Person *person )
{
    Node *new_node = malloc( sizeof( Node ) );
    int success = new_node != NULL;

    if ( success )
    {
        new_node->person = *person;
        new_node->prev   = list->tail;
        new_node->next   = NULL;

        if ( list->tail == NULL )
        {
            list->head = list->tail = new_node; 
        }
        else
        {
            list->tail = list->tail->next = new_node;
        }
    }

    return success;
}

void display( const List *list )
{
    for ( Node *current = list->head; current != NULL; current = current->next )
    {
        printf( "code = %d, name = %s, job = %s, salary = %d\n",
                current->person.code, current->person.name, 
                current->person.job, current->person.salary );
    }
}

void swap( Node **current )  
{  
    Node *tmp = *current;  

    *current = ( *current )->next;  

    tmp->next = ( *current )->next;
    ( *current )->next = tmp;

    ( *current )->prev = tmp->prev;
    tmp->prev = *current;

    if ( tmp->next != NULL )
    {
        tmp->next->prev = tmp;
    }
}

void clear( List *list )
{
    while ( list->head != NULL )
    {
        Node *current = list->head;
        list->head = list->head->next;
        free( current );
    }

    list->tail = list->head;
}

void sort( List *list, int cmp( const void *, const void * ) )
{
    if ( list->head != NULL )
    {
        int first_iteration = 1;

        for ( Node **first = &list->head, *sorted = NULL, *last = NULL;
              ( *first )->next != last;
              last = sorted )
        {
            Node **current = first;
            sorted = ( *first )->next;

            for ( ; ( *current )->next != last; current = &( *current )->next )
            {
                if ( cmp( &( *current )->person, &( *current )->next->person ) > 0 )
                {
                    swap( current );
                    sorted = ( *current )->next;
                }
            }

            if ( first_iteration )
            {
                list->tail = *current;
                first_iteration = 0;
            }               
        }             
    }         
}

int cmp_by_salary( const void *a, const void *b )
{
    const Person *left  = a;
    const Person *right = b;

    return ( right->salary < left->salary ) - ( left->salary < right->salary );
}

int cmp_by_code( const void *a, const void *b )
{
    const Person *left  = a;
    const Person *right = b;

    return ( right->code < left->code ) - ( left->code < right->code );
}

int cmp_by_name( const void *a, const void *b )
{
    const Person *left  = a;
    const Person *right = b;

    return strcmp( left->name, right->name );
}

int main(void) 
{
    List list = { .head = NULL, .tail = NULL };

    Person person[] =
    {
        { .code = 1, .name = "RaCo", .job = "programmer", .salary = 1000 },
        { .code = 2, .name = "Another RaCo", .job = "programmer", .salary = 500 },
        { .code = 3, .name = "One more RaCo", .job = "programmer", .salary = 1500 },
    };
    const size_t n = sizeof( person ) / sizeof( *person );

    puts( "Original list:" );
    for ( size_t i = 0; i < n; i++ )
    {
        push_back( &list, person + i );
    }

    display( &list );
    putchar( '\n' );

    sort( &list, cmp_by_salary );

    puts( "list sorted by salary:" );
    display( &list );
    putchar( '\n' );

    sort( &list, cmp_by_name );

    puts( "list sorted by name:" );
    display( &list );
    putchar( '\n' );

    sort( &list, cmp_by_code );

    puts( "list sorted by code:" );
    display( &list );
    putchar( '\n' );

    printf( "Debug output. The pointer tail points to %s\n", list.tail->person.name );

    clear( &list );

    return 0;
}
正如您可以看到的,使用同一个函数sort,您可以按结构Person的任何数据成员对列表进行排序。每次必须更改排序条件时,无需编写新的排序函数

如果需要对列表进行排序,例如按数据成员薪资降序排序,则只需在比较函数的返回语句中交换变量即可

int cmp_by_salary( const void *a, const void *b )
{
    const Person *left  = a;
    const Person *right = b;

    return ( right->salary < left->salary ) - ( left->salary < right->salary );
}

首先,有一个拼写错误

typedef struct node {
   int code;
   char name[40];
   char job[40];
   int salary;
   struct nodo *next;
          ^^^^
   struct nodo *prev;
          ^^^^
} node;
应该有

typedef struct node {
   int code;
   char name[40];
   char job[40];
   int salary;
   struct node *next;
          ^^^^
   struct node *prev;
          ^^^^ 
} node;
其次,如果要对列表进行排序,则应该对其节点的顺序进行排序,而不是交换节点的数据成员的值。例如,在main中,可以声明指向某个节点的指针。如果要通过交换节点的数据成员的值对列表进行排序,则指针将无效,因为指向的节点的数据成员已更改

第三,应该将除指针next和prev之外的所有数据成员放在一个单独的结构中。在这种情况下,函数声明看起来要简单得多,因为您不需要向函数传递多个初始值设定项,而只需要传递一个结构类型的对象

比如说

typedef struct Person
{
    int  code;
    char name[N];
    char job[N];
    int  salary;
} Person;

typedef struct Node 
{
    Person person;  
    struct Node *prev;
    struct Node *next;
} Node;
typedef struct List
{
    Node *head;
    Node *tail;
} List;
最后,如果处理一个双链接列表,则假定可以在列表的开头和结尾添加新节点。这意味着您应该保留两个指针:一个指向列表的第一个节点,另一个指向列表的最后一个节点。这样做的结果是,您应该声明另外一个结构来描述列表,例如

typedef struct Person
{
    int  code;
    char name[N];
    char job[N];
    int  salary;
} Person;

typedef struct Node 
{
    Person person;  
    struct Node *prev;
    struct Node *next;
} Node;
typedef struct List
{
    Node *head;
    Node *tail;
} List;
现在,当一切准备就绪时,是时候展示如何将冒泡排序方法应用于这样一个列表了

这是一个演示程序

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

enum { N = 40 };

typedef struct Person
{
    int  code;
    char name[N];
    char job[N];
    int  salary;
} Person;

typedef struct Node 
{
    Person person;  
    struct Node *prev;
    struct Node *next;
} Node;

typedef struct List
{
    Node *head;
    Node *tail;
} List;

int push_back( List *list, const Person *person )
{
    Node *new_node = malloc( sizeof( Node ) );
    int success = new_node != NULL;

    if ( success )
    {
        new_node->person = *person;
        new_node->prev   = list->tail;
        new_node->next   = NULL;

        if ( list->tail == NULL )
        {
            list->head = list->tail = new_node; 
        }
        else
        {
            list->tail = list->tail->next = new_node;
        }
    }

    return success;
}

void display( const List *list )
{
    for ( Node *current = list->head; current != NULL; current = current->next )
    {
        printf( "code = %d, name = %s, job = %s, salary = %d\n",
                current->person.code, current->person.name, 
                current->person.job, current->person.salary );
    }
}

void swap( Node **current )  
{  
    Node *tmp = *current;  

    *current = ( *current )->next;  

    tmp->next = ( *current )->next;
    ( *current )->next = tmp;

    ( *current )->prev = tmp->prev;
    tmp->prev = *current;

    if ( tmp->next != NULL )
    {
        tmp->next->prev = tmp;
    }
}

void clear( List *list )
{
    while ( list->head != NULL )
    {
        Node *current = list->head;
        list->head = list->head->next;
        free( current );
    }

    list->tail = list->head;
}

void sort( List *list, int cmp( const void *, const void * ) )
{
    if ( list->head != NULL )
    {
        int first_iteration = 1;

        for ( Node **first = &list->head, *sorted = NULL, *last = NULL;
              ( *first )->next != last;
              last = sorted )
        {
            Node **current = first;
            sorted = ( *first )->next;

            for ( ; ( *current )->next != last; current = &( *current )->next )
            {
                if ( cmp( &( *current )->person, &( *current )->next->person ) > 0 )
                {
                    swap( current );
                    sorted = ( *current )->next;
                }
            }

            if ( first_iteration )
            {
                list->tail = *current;
                first_iteration = 0;
            }               
        }             
    }         
}

int cmp_by_salary( const void *a, const void *b )
{
    const Person *left  = a;
    const Person *right = b;

    return ( right->salary < left->salary ) - ( left->salary < right->salary );
}

int cmp_by_code( const void *a, const void *b )
{
    const Person *left  = a;
    const Person *right = b;

    return ( right->code < left->code ) - ( left->code < right->code );
}

int cmp_by_name( const void *a, const void *b )
{
    const Person *left  = a;
    const Person *right = b;

    return strcmp( left->name, right->name );
}

int main(void) 
{
    List list = { .head = NULL, .tail = NULL };

    Person person[] =
    {
        { .code = 1, .name = "RaCo", .job = "programmer", .salary = 1000 },
        { .code = 2, .name = "Another RaCo", .job = "programmer", .salary = 500 },
        { .code = 3, .name = "One more RaCo", .job = "programmer", .salary = 1500 },
    };
    const size_t n = sizeof( person ) / sizeof( *person );

    puts( "Original list:" );
    for ( size_t i = 0; i < n; i++ )
    {
        push_back( &list, person + i );
    }

    display( &list );
    putchar( '\n' );

    sort( &list, cmp_by_salary );

    puts( "list sorted by salary:" );
    display( &list );
    putchar( '\n' );

    sort( &list, cmp_by_name );

    puts( "list sorted by name:" );
    display( &list );
    putchar( '\n' );

    sort( &list, cmp_by_code );

    puts( "list sorted by code:" );
    display( &list );
    putchar( '\n' );

    printf( "Debug output. The pointer tail points to %s\n", list.tail->person.name );

    clear( &list );

    return 0;
}
正如您可以看到的,使用同一个函数sort,您可以按结构Person的任何数据成员对列表进行排序。每次必须更改排序条件时,无需编写新的排序函数

如果需要对列表进行排序,例如按数据成员薪资降序排序,则只需在比较函数的返回语句中交换变量即可

int cmp_by_salary( const void *a, const void *b )
{
    const Person *left  = a;
    const Person *right = b;

    return ( right->salary < left->salary ) - ( left->salary < right->salary );
}

使用node temp代替node*temp。然后将所有内容复制到temp结构中,如下所示:temp.salary=ptr1->salary、strcpytemp.name、ptr1->name等。最简单的解决方案是使用指向列表元素的临时指针数组,调用qsort对数组排序,然后使用排序后的数组重建列表。如果不想使用任何临时存储,则需要编写自己的合并排序或快速排序或类似内容。在列表上实现合并排序算法。该算法不需要随机访问元素。使用node temp代替node*temp。然后将所有内容复制到temp结构中,如下所示:temp.salary=ptr1->salary、strcpytemp.name、ptr1->name等。最简单的解决方案是使用指向列表元素的临时指针数组,调用qsort对数组排序,然后使用排序后的数组重建列表。如果不想使用任何临时存储,则需要编写自己的合并排序或快速排序或类似内容。在列表上实现合并排序算法。该算法不需要随机访问元素。非常感谢你!值得注意的是,此解决方案不交换节点;它在离开时交换内容
g按原始顺序创建节点链接。简而言之,这与您在动态节点顺序更改中想要的正好相反。理想情况下,在适当的解决方案中修改的惟一内容是指向next和prev节点成员的指针。这是本学术作业的发起者可能想要的解决方案。非常感谢!值得注意的是,此解决方案不交换节点;它交换内容的同时保持节点链接的原始顺序。简而言之,这与您在动态节点顺序更改中想要的正好相反。理想情况下,在适当的解决方案中修改的惟一内容是指向next和prev节点成员的指针。这就为这项学术任务的发起人提供了可能的解决方案。