写给自己看的单链表:快速排序
Posted lyrich
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了写给自己看的单链表:快速排序相关的知识,希望对你有一定的参考价值。
搬运自我的CSDN https://blog.csdn.net/u013213111/article/details/88670136
!!!Attention:以下操作中的单链表均带有头结点!!!
参考了这三篇文章:
单链表快速排序算法的实现
单链表的快速排序
单链表的快排实现
快速排序的思路是:首先,选取一个pivot;然后以pivot作为基准,对待排序的数据进行分区,得到两个部分,一个部分的数据均小于pivot,另一个部分的数据均大于pivot,然后对这两个部分再进行之前的操作,直至排序完成。
对数组来说,pivot通常会选取位于中间的数据,然后用两个指针分别从头、尾两端向中间移动。
但是对于单链表来说,由于只能从头到尾单方向进行移动,所以其快速排序的实现方式有所不同,取第一个节点为pivot(这里要注意开区间和闭区间的问题,下面细说),指针p从pivot开始向后移动,指针q从pivot->next开始向后移动,最后一步是交换pivot和p的值,最终呈现的结果是:从头结点至p-1(含p-1)之间的数据均小于pivot,从p+1(含p+1)至q之间的值均大于pivot。
用一个例子来看看Partition函数的思路:
下面看一下不同区间表达式下的代码,开区间和闭区间导致代码不同的思路来自于这篇文章:你常写的二分查找,真的是没有bug吗?
1.左闭右开,初始区间为 [head->next,NULL)
这是比较省事的一种表达方式。首先看QuickSort函数的循环条件,当left != right时继续排序,借用上面那篇文章中的一个例子来说就是:
由于我们采用的是左闭右开表示法,也就是 区间为 [left ,right) 且left == right 循环停止,,如果用个例子来解释,大家就会豁然开朗了, 假如[ left=4, right=4),此时用左闭右闭来解释的话,区间实际上是出现了右边界=3 , 左边界=4 , 这种情形,右边界 < 左边界,这意味着区间长度<=0 了,无法继续了。
在迭代的过程中,仍然要保持区间是左闭右开的。在第一次分区后,数据的两个部分分别表示为 [head->next,par) 和 [par->next, NULL),所以迭代的语句为QuickSort(head, left, par); QuickSort(head, par->next, NULL);注意Partation函数中的语句也要根据区间的左闭右开性质来写。
1 void QuickSort(Lnode *head, Lnode *left, Lnode *right) //left is head->next, right is null 2 { 3 if ( left != right) { //ATTENTION!!! 4 Lnode *par = Partation(left, right); 5 QuickSort(head, left, par); 6 QuickSort(head, par->next, NULL); 7 } 8 } 9 10 Lnode *Partation(Lnode *left, Lnode *right) 11 { 12 if (left == right) 13 return left; 14 15 Lnode *p, *q; 16 eletype pivot = left->data; 17 p = left; 18 q = p->next; 19 while (q != right) { 20 if (q->data < pivot) { 21 p = p->next; 22 SwapData(p, q); 23 } 24 q = q->next; 25 } 26 SwapData(left, p); 27 return p; 28 } 29 30 void SwapData(Lnode *p, Lnode *q) 31 { 32 eletype tmp; 33 tmp = p->data; 34 p->data = q->data; 35 q->data = tmp; 36 }
2.左开右开,初始区间为 (head,NULL)
这种表达方式使得调用函数时比较方便,因为参数直接就是head和NULL,但是写法比上一种稍麻烦了一点点。
QuickSort函数的循环条件发生了改变,当left->next != right时继续排序。在第一次分区后,数据的两个部分分别表示为 (head,par) 和 (par, NULL),所以迭代的语句为QuickSort(head, left, par); QuickSort(head, par, NULL);,Partation函数中的语句也要根据区间的左开右开性质来写。
1 void QuickSort(Lnode *head, Lnode *left, Lnode *right) 2 { 3 if (left->next != right) { 4 Lnode *par = Partation(left, right); 5 QuickSort(head, left, par); 6 QuickSort(head, par, NULL); 7 } 8 } 9 10 Lnode *Partation(Lnode *left, Lnode *right) 11 { 12 if (left->next->next == right) 13 return left->next; 14 15 Lnode *p, *q; 16 eletype pivot = left->next->data; 17 p = left->next; 18 q = p->next; 19 while (q != right) { 20 if (q->data < pivot) { 21 p = p->next; 22 SwapData(p, q); 23 } 24 q = q->next; 25 } 26 SwapData(left->next, p); 27 return p; 28 } 29 30 void SwapData(Lnode *p, Lnode *q) 31 { 32 eletype tmp; 33 tmp = p->data; 34 p->data = q->data; 35 q->data = tmp; 36 }
以上是关于写给自己看的单链表:快速排序的主要内容,如果未能解决你的问题,请参考以下文章