不同于数组快排和归并排序(见排序归纳总结(插入排序、归并排序、堆排序、快速排序、桶排序)),链表不能够随机访问,只能从链表头遍历至链表尾,针对这一特性,需要对数组的排序算法做相应的调整。
1. 快速排序
对于链表的快速排序,使用两个指针p和q,使得p和q都只向其next方向进行遍历,同时保证p之前的链表节点的val都小于head的val值,p和q之间的链表节点的val都大于head的val值,则当q遍历到链表末尾时,再将head的val和p的val值进行互换,则就进行了 一次paritition操作。
代码如下:
// ListQucikSort.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};
void insertNode(ListNode* head, ListNode* cur) {
cur->next = head->next;
head->next = cur;
return;
}
ListNode* partition(ListNode* head, ListNode* tail) {
ListNode *p = head, *q = head;
int pivot = head->val;
while (q != tail) {
if (q->val < pivot) {
p = p->next;
swap(p->val, q->val);
}
q = q->next;
}
swap(p->val, head->val);
return p;
}
ListNode* quickSort(ListNode* head, ListNode* tail) {
if (head == tail) return head;
ListNode* mid = partition(head, tail);
head = quickSort(head, mid);
quickSort(mid->next, tail);
return head;
}
ListNode* quickSortAll(ListNode* head) {
if (!head || !head->next) return head;
return quickSort(head, nullptr);
}
int main()
{
ListNode* head = new ListNode(-1);
insertNode(head, new ListNode(10));
insertNode(head, new ListNode(4));
insertNode(head, new ListNode(11));
insertNode(head, new ListNode(6));
insertNode(head, new ListNode(3));
insertNode(head, new ListNode(5));
insertNode(head, new ListNode(1));
head = quickSortAll(head->next);
ListNode* node = head;
while (node) {
cout << node->val << ' ';
node = node->next;
}
int x; cin >> x;
cout << endl;
return 0;
}
2. 归并排序
链表归并排序的重点在于,有序链表的合并(即merge操作,剑指 Offer 25. 合并两个排序的链表)和链表中点的查找(查找到中间节点以便进行归并,运用快慢指针,876. 链表的中间结点)。
代码如下:
// 链表的归并排序.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};
void insertNode(ListNode* head, ListNode* cur) {
cur->next = head->next;
head->next = cur;
return;
}
ListNode* mergeList(ListNode* l1, ListNode* l2) { //进行链表合并
if (!l1) return l2;
if (!l2) return l1;
ListNode* head = l1->val > l2->val ? l2 : l1; //head节点作为合并后链表的头节点
l1 = head == l1 ? l1->next : l1;
l2 = head == l2 ? l2->next : l2;
ListNode* tail = head; //tail节点作为helper指针,向合并的链表添加节点
while (l1 && l2) {
if (l1->val > l2->val) { tail->next = l2; l2 = l2->next; }
else { tail->next = l1; l1 = l1->next; }
tail = tail->next;
}
while(l1) { tail->next = l1; l1 = l1->next; tail = tail->next; }
while(l2) { tail->next = l2; l2 = l2->next; tail = tail->next; }
return head;
}
ListNode* mergeSortList(ListNode* head) {
if (!head || !head->next) return head;
ListNode *fast = head, *slow = head;
//查找中间节点,要保证链表的长度大于2,
//若是等于2,则无需寻找中点,即下面赋值操作后
//l = head和r = head->next是正确的,
//否则fast = null,slow->next = nullptr
//则下面语句中的slow->next出错
while (fast->next && fast->next->next) {
fast = fast->next->next;
slow = slow->next;
}
ListNode* l = head, * r = slow->next;
//中间节点后的第一个节点作为需合并链表头节点
slow->next = nullptr; //中间节点的next指向空,以适应merge操作
l = mergeSortList(l);
r = mergeSortList(r);
return mergeList(l, r);
}
int main()
{
ListNode* head = new ListNode(-1);
insertNode(head, new ListNode(10));
insertNode(head, new ListNode(4));
insertNode(head, new ListNode(11));
insertNode(head, new ListNode(6));
insertNode(head, new ListNode(3));
insertNode(head, new ListNode(5));
insertNode(head, new ListNode(1));
head = mergeSortList(head->next);
ListNode* node = head;
while (node) {
cout << node->val << ' ';
node = node->next;
}
cout << endl;
return 0;
}