一.快速排序最坏状况分析java
上篇文章分析到快速排序-----排序之快速排序 。最后提到了一个思考题,什么样的状况下快速排序是最坏状况?算法
有两种状况:数组
数组已经排好序(升序或者逆序)优化
这种状况,挑选了第一个元素为主元,那么主元就是数组中最大的或者是最小的,n划分红1和n-1ui
时间复杂度T(n)=T(n-1)+T(1)+θ(n) 根据递归公式求得T(n)=O(n^2),和插入排序同样。spa
数组全部元素都是重复的.net
这种状况和第一种状况同样,也是划分红1和n-1,时间复杂度T(n)=O(n^2)code
二.快速排序优化orm
那么该如何优化才能让快排时间复杂度不超过O(nlgn)呢?blog
(1) 针对第一种状况,有两种方法:① 随机挑选主元;②打乱数组的顺序。咱们以前的算法是挑选第一个元素为主元,若是是随机挑选,就避免了最坏状况的第一种。或者在数组划分前,先打乱数组的顺序,也能够达到一样效果
(2)第二种状况,若是数组有大量的重复元素,那么快速排序效率会大大下降,划分的效果不理想,为何?能够本身想一下,怎么解决呢?能够用三向切分快速排序。
三向切分快速排序示意图:
就是把数组分为三份,小于主元,等于主元,大于主元 三份。
如:把{1,5,7,5,9,3,8,6,4,5}====>{1,3,4,5,5,5,7,9,8},这样的话,等于主元的那一份就不用作递归,若是有大量重复的元素这种算法就比原始快排效率高不少,若是所有元素都是重复的,三向切分快速的时间复杂度为O(n)。
三.三向切分快速算法过程
如何才能把数组三等份,下面咱们经过例子来描述算法 a(n)={1,5,7,5,9,3,8,6,4,5}
1 5 7 5 9 3 8 6 4 5
lt i gt
设v =a[0] 比较v和a[i]
a[i]<v,交换a[lt]和a[i],lt和i都加1
a[i]>v 交换a[gt]和a[i],gt减1
a[i]=v i加1
循环一直到i>gt,算法结束。
四.三向切分快速算法代码实现
/** * 快速排序 * */ public class Quicksort { public Quicksort() { // TODO Auto-generated constructor stub } // 3向切分快速排序 public static void sort3way(int[] arry, int low, int hight) { if (hight < low) return; int lt = low, i = low + 1, gt = hight; int pivot = arry[low]; int temp = 0; while (i <= gt) { if (arry[i] < pivot) { // 交换arry[i]和a[lt] temp = arry[lt]; arry[lt] = arry[i]; arry[i] = temp; lt++; i++; } else if (arry[i] > pivot) { // 交换arry[i]和a[gt] temp = arry[gt]; arry[gt] = arry[i]; arry[i] = temp; gt--; } else { i++; } } sort3way(arry, low, lt - 1); sort3way(arry, gt + 1, hight); } public static void main(String[] args) { int[] arry = { 1, 5, 7, 5, 9, 3, 8, 6, 4, 5 }; sort3way(arry, 0, arry.length - 1); for (int n : arry) { System.out.println(n); } } }