如果你还不了解快速排序,强烈推荐你可以先移步到我的另外一篇博客 快速排序的引入 — 荷兰国旗问题
我们先看看快排 1.0 的算法思路:
我们每次选择最后一个元素作为我们的基准值,然后我们将小于等于基准值的放在基准值左边,大于基准值的放在基准值右边,这时基准值的位置已经排好 (因为小于等于基准值的已经都在基准值的左边,大于基准值的已经在基准值的右边)
再分别递归基准值左边部分和右边部分;因为每次递归总能使一个数变得有序,所以多次递归最终能使数组变得有序
现在看看快排 2.0 的算法思路:
快排 2.0 类似荷兰国旗问题,我们同样选择每次最后一个元素作为我们的基准值,这次我们将等于基准值的放中间,小于基准值的放左边,大于基准值的放右边,这样我们一次就可以完成一堆等于基准值的位置的排序
再分别递归基准值左边部分和右边部分;因为每次递归总能使一堆数变得有序,所以多次递归最终能使数组变得有序
总结:
无论快排 1.0 还是快排 2.0,算法时间复杂度都是 O(N²),因为我们可以举出一个最差的例子:arr = [1, 2, 3, 4, 5, 6, 7, 8, 9],全部范围中我们以最后一个元素 9 作为基准值进行划分,这一轮我们只搞定了 9 ,没有右侧区域,只有左侧区域;第二轮只搞定了 8,没有右侧区域,只有左侧区域...依次类推,每次都只搞定了一个数,每次比较次数从 n-1 到 1,为等差数列,所以时间复杂度为 O(N²)
造成这种情况的原因在于划分值打的很偏,最好的划分值为正好打在中间,使左右两侧递归的规模差不多,这时候 T(N) = 2T(N/2) + O(N) ( 这个 O(N) 就是 partition 所需的时间复杂度,在完成荷兰国旗分两类[小于等于、大于]和分三类[小于、等于、大于]时,时间复杂度都为 O(N),有困惑的小伙伴可以去看看我的这篇博客 快速排序的引入 — 荷兰国旗问题)
我们都知道这种式子得到的时间复杂度为 O(NlogN),划分值如果打偏,就会逐渐退化成 O(N²)
因为我们总是拿最后一个元素作为划分值,所以我们总能举出最差情况的例子,因此我们引出快排 3.0版本
快排 3.0 的算法思路:
我们在数组中随机选一个数作为划分值,这样好情况和坏情况出现的可能性是一样的,是等概率事件,由数学期望求概率累加得到这个算法时间复杂度为 O(NlogN) , 具体怎么求,感兴趣的小伙伴可以自己搜索一下
public class QuickSort { public static void main(String[] args) { int[] arr = new int[]{3, 5, 2, 1, 6, 4, 4, 7, 5}; quickSort(arr, 0, arr.length-1); System.out.println(Arrays.toString(arr)); } public static void quickSort(int[] arr, int L, int R) { if (L < R) { // 得到随机数作为划分值 int num = arr[(int) (Math.random() * (R - L + 1))]; int[] p = partition(arr, L, R, num); quickSort(arr, L, p[0] - 1); quickSort(arr, p[1] + 1, R); } } public static int[] partition(int[] arr, int L, int R, int num) { int less = L; int more = R; while (L < more + 1){ if (arr[L] < arr[R]) { swap(arr, less++, L++); }else if (arr[L] > arr[R]) { swap(arr, more--, L); }else { L++; } } return new int[]{less, more}; } public static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }
输出结果如下
如果我们已经了解了荷兰国旗问题的解法,那快排简直就是小 case 了,如果有看不懂 partition 方法的小伙伴,可以去 快速排序的引入 — 荷兰国旗问题相关代码部分 看看对应的代码注释
空间复杂度
我们已经知道快速排序的时间复杂度为 O(NlogN),那么它的空间复杂度为多少呢?快排使用了递归,在最优情况下,使用到的栈空间为 O(logN), 最坏的情况下为 O(N),而好情况和坏情况出现的可能性是一样的,是等概率事件,最后可以得到平均空间复杂度为 O(logN)(具体求法,感兴趣的小伙伴可以自己研究一下)
算法稳定性
该算法是不稳定的算法,因为元素的交换是跳跃进行的
欢迎来逛逛我的博客 mmimo技术小栈