题目:对单链表进行排序,要求不改变每个节点内的值。
1.首先自然而然地会想到快速排序,毕竟是一个经典的排序算法。但是在排序过程中要求不能改变节点中的值,就必须通过改变节点中的指针来交换节点。而且快速排序的时间复杂度的下限是O(N^2),当链表接近有序时,可能还没有插入排序来的快。
直接上代码(代码是康神 撸的,我太菜撸不出来)
//List Quick Sort
class Solution {
public:
ListNode* sortList(ListNode* head) {
if (head == NULL) return head;
ListNode dummy(-1);
dummy.next = head;
quicksort(&dummy, NULL);
return dummy.next;
}
private:
void quicksort(ListNode* pre, ListNode* end) {
if ( pre->next == end|| pre->next->next == end)
return;
ListNode* pivotpos = partition(pre, end);
quicksort(pre, pivotpos);
quicksort(pivotpos, end);
}
ListNode* partition(ListNode* pre, ListNode* end)
{
ListNode* prehead = pre;
ListNode* head = pre->next;
ListNode* prepivotpos = pre;
ListNode* pivotpos = pre->next;
ListNode* swapnode = pivotpos->next;
ListNode* preswap = pivotpos;
int pivot = pivotpos->val;
while (swapnode != end)
{
if (swapnode->val < pivot)
{
prepivotpos = pivotpos;
pivotpos = pivotpos->next;
if (pivotpos != swapnode)
swapLink(prepivotpos, pivotpos, preswap, swapnode);
}
preswap = swapnode;
swapnode = swapnode->next;
}
swapLink(prehead, head, prepivotpos, pivotpos);
return pivotpos;
}
void swapLink(ListNode* &prepivotpos, ListNode* &pivotpos, ListNode* &preswap, ListNode* &swapnode)
{
if (pivotpos->next == swapnode)
{
ListNode* end = swapnode->next;
prepivotpos->next = swapnode;
swapnode->next = pivotpos;
pivotpos->next = end;
}
else
{
ListNode* endpivot = pivotpos->next;
ListNode* endswap = swapnode->next;
prepivotpos->next = swapnode;
swapnode->next = endpivot;
preswap->next = pivotpos;
pivotpos->next = endswap;
}
swap(pivotpos, swapnode);
}
};
2.其实这是leetcode上的原题,但是原题并没有规定不能改变节点中的值。上述代码在leetcode中运行超时,主要原因在于,当测试用例中包含大量重复值的时候,快排性能迅速下降,所以改用三路快排的方法,以pivot为基准值把原链表分成小于、等于、大于pivot的三条链表,分别递归排序后再串联。
//List three-way Quick Sort
class Solution {
public:
ListNode* sortList(ListNode* head) {
if (NULL == head || NULL == head->next) return head;
int pivot = head->val;
ListNode less(-1), equal(-1), greater(-1);
ListNode *lt = &less, *eq = &equal, *gt = &greater;
while (head != NULL) {
if (head->val < pivot) {
lt->next = head;
lt = lt->next;
head = head->next;
lt->next = NULL;
}
else if (head->val > pivot) {
gt->next = head;
gt = gt->next;
head = head->next;
gt->next = NULL;
}
else {
eq->next = head;
eq = eq->next;
head = head->next;
eq->next = NULL;
}
}
ListNode* left = sortList(less.next);
ListNode* right = sortList(greater.next);
if (NULL == left) {
left = equal.next;
}
else {
lt = &less;
while (lt->next != NULL) lt = lt->next;
lt->next = equal.next;
}
eq = &equal;
while (eq->next != NULL) eq = eq->next;
eq->next = right;
return left;
}
};
3.链表排序也适合用归并排序,且时间复杂度的下限是O(NlogN),只是在遍历寻找链表的中间节点的时候比较费时,处理大量数据的时候尤其突出。
//List Merge Sort
class Solution {
public:
ListNode* sortList(ListNode* head) {
if (!head || !head->next) return head;
ListNode *fast = head, *slow = head;
while (fast->next&&fast->next->next)
{
fast = fast->next->next;
slow = slow->next;
}
fast = slow->next;
slow->next = NULL;
ListNode *l1 = sortList(head);
ListNode *l2 = sortList(fast);
return mergeTwoLists(l1, l2);
}
private:
ListNode* mergeTwoLists(ListNode* lhs, ListNode* rhs) {
ListNode dummy(-1);
ListNode *cur = &dummy;
while (lhs&&rhs)
if (lhs->val < rhs->val)
{
cur->next = lhs;
cur = lhs;
lhs = lhs->next;
}
else
{
cur->next = rhs;
cur = rhs;
rhs = rhs->next;
}
if (lhs)
cur->next = lhs;
if (rhs)
cur->next = rhs;
return dummy.next;
}
};
关于三路快排与双基准排序,准备有时间了再写一个总结。
http://www.cnblogs.com/chenying99/archive/2014/07/10/3836816.html