快排代码的第一句即是选取基准点,此后数据的移动根据这个基准点的大小进行调整,若是基准点选取的很差,将会致使快排的效率低下,通过测试,普通的快排算法针对(1)近乎有序的数列;(2)含有大量重复数据的数列;这两种状况时效率将会变得很是低,针对这些状况,通过适当的优化可使快排达到很高的效率。算法
快排将选取的基准点通过调整放到合适的位置,以后将这个基准点左右两边的区间分别递归的进行快排,若是基准点的数据比较小,将会致使调整后基准点处于靠近两侧的位置,那么两边的区间长度将会严重失去平衡数组
对于一个近乎有序的数列,当直接使用第一个元素做为基准点的时候,将会致使下图的状况函数
若是数列很是接近有序测试
能够看到此时快排的递归过程生成的递归树的平衡性很是差,不能保证高度是logn,进而致使了效率变低,针对这种状况,只需改变选取基准点的方式就能够提升算法的效率。优化
三数取中法:指的是选取基准点以前咱们能够拿出数列中间位置元素的值,将它和首尾的元素进行比较,以后将这三个数中的中间大的数交换到数列首位的位置,以后将这个数做为基准点,尽可能减少以后的分区后左右两边的区间长度之差。ui
随机交换法:指的是选取基准点以前设计随机种子,经过随机函数获得一个在数列长度内的数,将这个随机数做为索引所指的数和第一个元素进行交换,以后将首位元素做为基准点。即随机选一个数放到首位的地方。这样一来,第一次就将最小的数交换到首位的几率是很是小的,第二次将次小的数交换到首位的几率依然很是的小。设计
好比随机生成一个含有15万个数据的数组,范围是从0~10,那么数组中将含有很是多的重复数据,对这个数组使用上述的快排排序时,时间几乎又是回到了O(n^2)的级别,缘由以下3d
在以前的分区算法中,因为含有大量的重复数据,将会致使分出来的左右区间如图所示,两个区间的长度比例彻底失衡,致使了算法的时间复杂度上升,针对这种状况,须要对分区操做作适当的修改,思路是将小于基准点的数所有放到左边,大于基准点的数所有放到右边,code
具体操做:从右向左扫描时,若是元素值大于基准点,则继续,不然中止,如图j所指的位置,从左向右扫面时,当元素值小于基准点,则继续,不然中止,如图i所指的位置blog
通过上述扫描后,i和j停在了相应的位置,此时要作的是,交换i和j分别所指的元素便可,这样一来,左边的所有都是小于等于基准点的,右边的所有都是大于等于基准点的,这样作的好处是,对于等于基准点的元素,将他们分别放到了左右的两个区间,而不是像以前那样彻底放在同一边,致使区间长度不平衡。所以,经过将等于基准点的元素分配到不一样区间,保证了左右区间长度尽量平衡,提高了算法的效率
代码
template<typename T> int partion2(T k[], int l, int r) { swap(k[l], k[rand() % (r - l + 1) + l]); T temp = k[l]; int i = l + 1, j = r; while (true) { while (i <= r && k[i] < temp) i++; while (j >= l && k[j] > temp) j--; if (i > j) break; swap(k[i], k[j]); i++; j--; } swap(k[l], k[j]); return j; } template<typename T> void QSort2(T k[], int l, int r) { if (l < r) { int p = partion2(k, l, r); QSort2(k, l, p - 1); QSort2(k, p + 1, r); } } template<typename T> void QuickSort2(T k[], int len) { srand(time(NULL)); QSort2(k, 0, len - 1); }
通过测试,对于含有大量重复数据的数组,算法的效率基本回到了O(nlogn)的级别。
3路法一样是针对含有大量重复数列的优化,不一样于以前的快排方法,3路法的思想是将数列分红3个区间,分别是小于、等于和大于基准点的区间,那么分区以后,对于等于基准点的区间内的元素,咱们就不须要对其作任何处理了,只须要递归的处理小于和大于基准点的元素便可。
如图,须要多设置几个索引,橙色部分所有是小于v的数据,紫色为大于v的数据,i所指的为待处理的数据。
(1)当待处理的数据小于v时,只需将i所指的元素和等于v的区间的第一个元素交换便可,即将e换到lt以后的位置,lt++,i++
(2)i所指元素大于v时,将其换到大于基准点的区间的第一个位置便可,即交换i和gt-1的元素,gt--,i不变
(3)i所指元素等于v时,直接i++
代码
template<typename T> void QSort3Ways(T k[], int l, int r) { if (r - l <= 15) { InsertSort(k, l, r); return; } swap(k[l], k[rand() % (r - l + 1) + l]); T temp = k[l]; int lt = l; // k[l+1...lt] < v int gt = r + 1; // k[gt...r] > v int i = l + 1; // k[lt+1...i) = v while (i < gt) { if (k[i] < temp) { swap(k[i], k[lt + 1]); i++; lt++; } else if (k[i] > temp) { swap(k[i], k[gt - 1]); gt--; } else { i++; } } swap(k[l], k[lt]); QSort3Ways(k, l, lt - 1); QSort3Ways(k, gt, r); } template<typename T> void QuickSort3Ways(T k[], int len) { srand(time(NULL)); QSort3Ways(k, 0, len - 1); }