快速排序的稳定化实现
来源:互联网 发布:mac 不能剪切 编辑:程序博客网 时间:2024/05/21 19:27
稳定排序的概念:
保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。
例如:a[i]==a[j]&&i
通常的快速排序为什么不稳定?
快速排序初始的版本:
int partition(vector<int>&a, int s, int e) { if (s < e) { int low = s, high = e, key = a[s]; while (low < high) { while (low < high && a[high] >= key) high--; if (low < high) { a[low++] = a[high];//将比key小的元素移到低端 } while (low < high && a[low] < key) low++; if (low < high) { a[high--] = a[low];//将比key大的元素移到高端 } } a[low] = key; return low; } return -1;}void quick_sort(vector<int> & a,int s, int e) { if (s < e) { int k = partition(a, s, e); quick_sort(a, s, k); quick_sort(a, k + 1,e); }}
看看交换导致的不稳定:
以下是初始序列(第一行是在原始数组的下标,第二行是元素值,若有第三行是当前数组的下标):
说明:low,high指的下标都是第三行当前数组内的下标。
1)以34为key进行划分,low=0,high=9:
找到第一个要交换到低端的元素21,low=0,high=6,将它换到0位置后,low=1,high=6;
将位于6位置的21换到首位时,这时已经不是稳定的了,因为它位于a[1]=21的前面;
从low=1开始向后找,下面在找需要移到高端的元素位于low=2的53,low=2,将它换到6位置:
交换后:
此时,high=5,low=2;
从high=5开始往前找,遇到a[3]=8停止,将a[3]换到low=2的位置。
此时,low=high=3结束;
最后,将key放到a[low],完成了一次划分。
因此,上面划分时的交换不能保证稳定性。
改进:稳定版
在交换是用额外的空间存储要交换的数据,具体:
int stable_partition(vector<int>& a, int s, int e) { if (s >= e) return s; vector<int> b(a.size()); int pa1, pa2, pb1, pb2; pa1 = pb1 = s; pa2 = pb2 = e; int start = s, end = e; int key = a[s]; while (pa1 < pa2) { while (pa1 < pa2 && a[pa1] < key) { a[s++]= a[pa1++]; } while (pa1 < pa2 && a[pa2] >= key) { a[e--]= a[pa2--] ; } if (pa1 < pa2) { b[pb1++]= a[pa1++]; b[pb2--]= a[pa2--] ; } } int i; for (i = pb2 + 1; i <= end; i++) a[s++] = b[i]; int idx = pa1; for (i = start; i < pb1; i++) a[s++] = b[i]; return idx;}
仍然以上面的序列为例:
这里用原数组a存储不需要交换位置的元素,如果要发生交换,放到b中。
它的一次划分过程如下,以key=a[1]=34为主元:
a数组:
b数组:
pa1=0开始,pa2=9开始,发现当pa1=0,pa2=6时需要交换;
此时,不进行交换,而是将pa1的数据放到b的首端,pa2的数据放到末端:
a数组:
b数组:
从pa1=1,pa2=5开始,继续向中间遍历,当不需要交换时,数据向两端补齐,要交换时,放入b中,下次要交换发生在pa1=2,pa2=3,此时
a数组:
b数组:
下一次,pa1=3,pa2=4,结束。
下面就是整合两个数组,结束时a的指针,s=2,
现将b后面的数组接上去,再把b前面的部分接上去,最后得到:
a数组:
可以看出这种划分结束时,以a[3]=34划分的结果保证了相等元素在划分后,下标的有序,所以这种快排是稳定的。
参考:
邵顺增. 稳定快速排序算法研究[J]. 计算机应用与软件, 2014, 31(7):263-266.
- 快速排序的稳定化实现
- java实现稳定的快速排序
- 快速排序的稳定化版本
- 快速排序的稳定算法
- 快速排序不是一个稳定的排序
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法
- 稳定,快速的xmonad
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法, 冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
- 常用的排序:快速排序、合并排序(稳定)--合并排序
- 稳定的排序算法
- 排序算法的稳定
- 快速排序的实现
- 快速排序的实现
- 快速排序的实现
- 快速排序的实现
- 快速排序的实现
- app电量测试
- 187. Repeated DNA Sequences
- caffe1源码解析从入门到放弃1):内存管理syncedmem.hpp / syncedmem.cpp
- 排序算法(九)——八大排序算法总结
- thinkphp3.2.1分页路由
- 快速排序的稳定化实现
- js、jQuery、layer实现弹出层的打开、关闭
- java在list集合指定位置插入对象和js在数组指定位置插入对象的方法
- java线程
- ECMAScript6(6):数组的扩展
- 最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等
- 进程间通信----信号量
- New Year Table
- EL表达式