快排的核心在于根据哨兵将节点二分,使用双指针分别从头和尾开始遍历即可完成。可是链表的访问时单向的,无法使用一个指针从后往前访问节点。
换个思路来解,我们的目的还是要将数据二分嘛。还是用双指针,慢指针 i 指向头结点,快指针 j 从第二个节点开始遍历,一旦遇到节点值小于哨兵的key,那说明 j 指向的节点应该在哨兵前,这时候我们将慢指针后移一步,然后替换 i 和 j 的值。替换后保证了 j 的值大于key,i 指向的值小于 key。而之前 i 指向的值肯定是大于key的,因为 j 先访问过 现在 i 指向的节点,j 访问过的节点肯定大于key。通过快慢指针就实现了将所有小于key的值移到前面,大于key的移到后面。最后再将key与 i 指向的节点替换。最终得到的链表被哨兵节点分开来。
剩余的操作和快排一样了,递归地快排下去。
/*
2,3,1,4,5
*/
ListNode* ListPartition(ListNode* root, ListNode* end)
{
int key = root->val;
ListNode* i=root, * j=root->next; // i 指向慢指针,j指向快指针
while (j!=end)
{
if (j->val < key)
{
i = i->next;
swap(i->val, j->val);
}
j = j->next;
}
swap(i->val, root->val);
return i;
}
void quickSort(ListNode* root,ListNode* end)
{
if (root == end) return;
ListNode* patition = ListPartition(root,end);
quickSort(root, patition);
quickSort(patition->next,end);
}
int main()
{
ListNode* p1 = new ListNode(3);
ListNode* p2 = new ListNode(2);
ListNode* p3 = new ListNode(1);
ListNode* p4 = new ListNode(4);
p1->next = p2;
p2->next = p3;
p3->next = p4;
quickSort(p1,NULL);
while (p1)
{
cout << p1->val<<" ";
p1 = p1->next;
}
system("pause");
}