C语言中如何用链表进行排序
在C语言中使用链表进行排序时,我们可以选择多种不同的排序算法来实现,比如插入排序、快速排序、归并排序等。归并排序在链表上的表现尤为出色,因为它不需要随机访问元素,只需进行顺序访问。下面我们详细讨论使用归并排序来对链表进行排序的过程。
一、链表的基本操作
在进行排序之前,我们需要了解链表的一些基本操作,包括创建链表、插入节点、删除节点以及遍历链表。
1. 创建链表
在C语言中,链表通常由一个结构体表示,每个结构体包含数据域和指向下一个节点的指针。
struct Node {
int data;
struct Node* next;
};
2. 插入节点
插入节点是链表操作的基础,可以在链表的头部、尾部或中间插入节点。
void insertAtHead(struct Node head, int data) {
struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = *head;
*head = newNode;
}
3. 删除节点
删除节点时需要找到要删除的节点并调整前一个节点的指针。
void deleteNode(struct Node head, int key) {
struct Node* temp = *head;
struct Node* prev = NULL;
if (temp != NULL && temp->data == key) {
*head = temp->next;
free(temp);
return;
}
while (temp != NULL && temp->data != key) {
prev = temp;
temp = temp->next;
}
if (temp == NULL) return;
prev->next = temp->next;
free(temp);
}
4. 遍历链表
遍历链表可以打印链表中的每个节点的数据。
void printList(struct Node* node) {
while (node != NULL) {
printf("%d -> ", node->data);
node = node->next;
}
printf("NULLn");
}
二、归并排序在链表中的实现
归并排序是一种有效的排序算法,尤其适合链表,因为它不需要随机访问元素。我们将归并排序分为两个部分:拆分链表和合并排序后的链表。
1. 拆分链表
拆分链表的目的是将链表分成两个子链表,直到每个子链表只有一个节点。
struct Node* getMiddle(struct Node* head) {
if (head == NULL) return head;
struct Node* slow = head;
struct Node* fast = head->next;
while (fast != NULL) {
fast = fast->next;
if (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
}
return slow;
}
2. 合并排序后的链表
合并两个排序后的链表是归并排序的核心步骤。
struct Node* sortedMerge(struct Node* a, struct Node* b) {
struct Node* result = NULL;
if (a == NULL) return b;
if (b == NULL) return a;
if (a->data <= b->data) {
result = a;
result->next = sortedMerge(a->next, b);
} else {
result = b;
result->next = sortedMerge(a, b->next);
}
return result;
}
3. 归并排序的主函数
归并排序的主函数将链表拆分并递归地排序和合并。
void mergeSort(struct Node headRef) {
struct Node* head = *headRef;
struct Node* a;
struct Node* b;
if ((head == NULL) || (head->next == NULL)) {
return;
}
struct Node* middle = getMiddle(head);
struct Node* nextOfMiddle = middle->next;
middle->next = NULL;
mergeSort(&head);
mergeSort(&nextOfMiddle);
*headRef = sortedMerge(head, nextOfMiddle);
}
三、应用示例
以下是一个完整的示例,展示如何使用归并排序对链表进行排序。
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
void insertAtHead(struct Node head, int data) {
struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = *head;
*head = newNode;
}
struct Node* getMiddle(struct Node* head) {
if (head == NULL) return head;
struct Node* slow = head;
struct Node* fast = head->next;
while (fast != NULL) {
fast = fast->next;
if (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
}
return slow;
}
struct Node* sortedMerge(struct Node* a, struct Node* b) {
struct Node* result = NULL;
if (a == NULL) return b;
if (b == NULL) return a;
if (a->data <= b->data) {
result = a;
result->next = sortedMerge(a->next, b);
} else {
result = b;
result->next = sortedMerge(a, b->next);
}
return result;
}
void mergeSort(struct Node headRef) {
struct Node* head = *headRef;
struct Node* a;
struct Node* b;
if ((head == NULL) || (head->next == NULL)) {
return;
}
struct Node* middle = getMiddle(head);
struct Node* nextOfMiddle = middle->next;
middle->next = NULL;
mergeSort(&head);
mergeSort(&nextOfMiddle);
*headRef = sortedMerge(head, nextOfMiddle);
}
void printList(struct Node* node) {
while (node != NULL) {
printf("%d -> ", node->data);
node = node->next;
}
printf("NULLn");
}
int main() {
struct Node* head = NULL;
insertAtHead(&head, 15);
insertAtHead(&head, 10);
insertAtHead(&head, 5);
insertAtHead(&head, 20);
insertAtHead(&head, 3);
insertAtHead(&head, 2);
printf("Unsorted list: n");
printList(head);
mergeSort(&head);
printf("Sorted list: n");
printList(head);
return 0;
}
四、其他排序算法在链表中的实现
除了归并排序,链表还可以使用其他排序算法,比如插入排序和快速排序。
1. 插入排序
插入排序适用于链表,因为它可以在O(1)时间内完成插入操作。
void sortedInsert(struct Node headRef, struct Node* newNode) {
struct Node* current;
if (*headRef == NULL || (*headRef)->data >= newNode->data) {
newNode->next = *headRef;
*headRef = newNode;
} else {
current = *headRef;
while (current->next != NULL && current->next->data < newNode->data) {
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
}
void insertionSort(struct Node headRef) {
struct Node* sorted = NULL;
struct Node* current = *headRef;
while (current != NULL) {
struct Node* next = current->next;
sortedInsert(&sorted, current);
current = next;
}
*headRef = sorted;
}
2. 快速排序
快速排序在链表上实现相对复杂,但它的时间复杂度在平均情况下为O(n log n)。
struct Node* partition(struct Node* head, struct Node* end, struct Node newHead, struct Node newEnd) {
struct Node* pivot = end;
struct Node* prev = NULL;
struct Node* cur = head;
struct Node* tail = pivot;
while (cur != pivot) {
if (cur->data < pivot->data) {
if ((*newHead) == NULL) {
(*newHead) = cur;
}
prev = cur;
cur = cur->next;
} else {
if (prev) {
prev->next = cur->next;
}
struct Node* temp = cur->next;
cur->next = NULL;
tail->next = cur;
tail = cur;
cur = temp;
}
}
if ((*newHead) == NULL) {
(*newHead) = pivot;
}
(*newEnd) = tail;
return pivot;
}
struct Node* quickSortRecur(struct Node* head, struct Node* end) {
if (!head || head == end) {
return head;
}
struct Node* newHead = NULL;
struct Node* newEnd = NULL;
struct Node* pivot = partition(head, end, &newHead, &newEnd);
if (newHead != pivot) {
struct Node* temp = newHead;
while (temp->next != pivot) {
temp = temp->next;
}
temp->next = NULL;
newHead = quickSortRecur(newHead, temp);
temp = getTail(newHead);
temp->next = pivot;
}
pivot->next = quickSortRecur(pivot->next, newEnd);
return newHead;
}
void quickSort(struct Node headRef) {
(*headRef) = quickSortRecur(*headRef, getTail(*headRef));
}
五、总结
在C语言中对链表进行排序时,选择合适的排序算法至关重要。归并排序由于其优良的性能和稳定性,通常是链表排序的首选。插入排序适用于小规模数据,而快速排序适用于需要更高效率的情况。无论选择哪种排序算法,都需要根据链表的具体情况进行调整和优化。在实际项目管理中,使用高效的项目管理系统如研发项目管理系统PingCode和通用项目管理软件Worktile,可以帮助团队更好地跟踪和管理开发进度,确保项目顺利进行。
相关问答FAQs:
Q: 如何在C语言中使用链表进行排序?
A: 链表排序是一种常见的操作,以下是一种基本的链表排序算法:
- 首先,定义一个指向链表头节点的指针,并将其初始化为NULL。
- 然后,创建一个新的链表节点,并将其插入到链表中的正确位置。这可以通过遍历链表并比较节点值来实现。
- 在比较节点值时,如果要插入的节点值小于当前节点值,则将要插入的节点插入到当前节点之前。
- 如果要插入的节点值大于当前节点值,则继续遍历链表直到找到合适的位置。
- 重复步骤3和步骤4,直到所有节点都被插入到新链表中。
- 最后,将原链表头节点指针指向新链表的头节点。
Q: 如何在C语言中实现链表的升序排序?
A: 以下是一种实现链表升序排序的方法:
- 首先,定义一个指向链表头节点的指针,并将其初始化为NULL。
- 然后,逐个读取输入的数据,并创建一个新的链表节点。
- 在插入新节点时,遍历链表并找到正确的位置。如果要插入的节点值小于当前节点值,则将要插入的节点插入到当前节点之前。如果要插入的节点值大于等于当前节点值,则继续遍历链表直到找到合适的位置。
- 重复步骤3,直到所有节点都被插入到链表中。
- 最后,将链表头节点指针指向排序后的链表的头节点。
Q: C语言中如何使用链表进行降序排序?
A: 以下是一种实现链表降序排序的方法:
- 首先,定义一个指向链表头节点的指针,并将其初始化为NULL。
- 然后,逐个读取输入的数据,并创建一个新的链表节点。
- 在插入新节点时,遍历链表并找到正确的位置。如果要插入的节点值大于当前节点值,则将要插入的节点插入到当前节点之前。如果要插入的节点值小于等于当前节点值,则继续遍历链表直到找到合适的位置。
- 重复步骤3,直到所有节点都被插入到链表中。
- 最后,将链表头节点指针指向排序后的链表的头节点。
原创文章,作者:Edit1,如若转载,请注明出处:https://docs.pingcode.com/baike/1041111