📅  最后修改于: 2023-12-03 14:54:42.708000             🧑  作者: Mango
排序链表是对链表进行排序的一种算法,常见的排序算法有冒泡排序、插入排序、选择排序、快速排序等。将一个无序的链表转化为有序的链表,可以方便地进行查找、插入、删除等操作。本文将介绍C语言中常见的排序链表算法,并给出相应的示例代码。
冒泡排序是一种基础的排序算法,基本思想是从左往右遍历链表,将相邻的两个节点比较,如果前面的节点值大于后面的节点值,则交换这两个节点的值,直到最后一个节点为止。这样可以确保最后一个节点是最大的节点。接下来,再从左往右遍历链表,但不包括最后一个节点,重复上述过程。时间复杂度为O(n^2)。
struct ListNode* bubbleSortList(struct ListNode* head) {
if(head == NULL || head->next == NULL) {
return head;
}
struct ListNode *p, *q, *end = NULL;
while(head->next != end) {
p = head;
while(p->next != end) {
q = p->next;
if(p->val > q->val) {
int temp = p->val;
p->val = q->val;
q->val = temp;
}
p = p->next;
}
end = p; // 最后一个已排序节点的指针
}
return head;
}
插入排序的基本思想是将一个无序的新节点插入到已排序的链表中,使得新的链表仍然有序。如果链表为空,则将新节点作为头结点。否则,从头结点开始往后遍历,找到第一个大于等于新节点的节点,将新节点插入到该节点的前面。时间复杂度为O(n^2)。
struct ListNode* insertionSortList(struct ListNode* head) {
if(head == NULL || head->next == NULL) {
return head;
}
struct ListNode *dummy = malloc(sizeof(struct ListNode));
dummy->next = head;
struct ListNode *cur = head->next, *prev = head;
while(cur != NULL) {
if(cur->val >= prev->val) {
prev = prev->next;
} else {
struct ListNode *p = dummy;
while(p->next->val <= cur->val) {
p = p->next;
}
prev->next = cur->next;
cur->next = p->next;
p->next = cur;
}
cur = prev->next;
}
return dummy->next;
}
选择排序是通过选择最小的节点,插入到有序的节点列表中对链表进行排序的一种算法。基本思想是从头结点开始遍历链表,查找链表中最小的节点,将该节点插入到已排序节点的末尾。因此,它需要两个指针:一个用于遍历未排序的节点,另一个用于指向已排序节点的末尾。
struct ListNode* selectionSortList(struct ListNode* head) {
if(head == NULL || head->next == NULL) {
return head;
}
struct ListNode *dummy = malloc(sizeof(struct ListNode));
dummy->next = head;
struct ListNode *tail = dummy; // 已排序节点的末尾指针
while(tail->next != NULL) {
struct ListNode *pre = tail, *cur = tail->next, *minp = pre, *min = cur;
while(cur != NULL) {
if(cur->val < min->val) {
min = cur;
minp = pre;
}
pre = cur;
cur = cur->next;
}
if(tail->next == min) {
tail = tail->next;
} else {
minp->next = min->next;
min->next = tail->next;
tail->next = min;
tail = tail->next;
}
}
return dummy->next;
}
快速排序是一种分治的排序算法,它利用了分治的思想,将一个大问题分解成几个小问题。基本思想是选定一个基准元素,将所有比它小的元素放在它的左边,所有比它大的元素放在它的右边,然后递归地处理左右两个子列表。时间复杂度为O(nlogn)。
struct ListNode* quickSortList(struct ListNode* head) {
if(head == NULL || head->next == NULL) {
return head;
}
struct ListNode *pivot = head, *p = head->next, *q, *left = NULL, *right = NULL;
while(p != NULL) {
q = p->next;
if(p->val < pivot->val) {
p->next = left;
left = p;
} else {
p->next = right;
right = p;
}
p = q;
}
left = quickSortList(left);
right = quickSortList(right);
pivot->next = right;
if(left == NULL) {
return pivot;
} else {
struct ListNode *tail = left;
while(tail->next != NULL) {
tail = tail->next;
}
tail->next = pivot;
return left;
}
}
以上是C语言中常见的几种排序链表算法的实现。选择合适的排序算法非常重要,通常取决于数据的大小和数据的分布情况。在实际使用中,可以根据实际情况灵活使用这些算法,以提高代码的效率和性能。