如何在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节点成员的指针。这就为这项学术任务的发起人提供了可能的解决方案。