一、快速排序的思想
首先你得了解快速排序的思想,一趟快速排序是将区间划分成了小于枢轴元素和大于枢轴元素的两个小区间,然后在这两个小区间内进行排序排序,直到区间长度小于等于1.
code leetcode 912: https://leetcode.cn/problems/sort-an-array/description/
class Solution {
public int pos(int[] nums, int l, int r){
int piv = nums[l];
while(l<r){
while(l<r && nums[r]>=piv) r--;
nums[l] = nums[r];
while(l<r && nums[l]<=piv) l++;
nums[r] = nums[l];
}
nums[l] = piv;
return l;
}
public void quickSort(int[] nums, int l, int r){
if(l>=r) return;
int mid = pos(nums, l, r);
quickSort(nums, l , mid-1);
quickSort(nums, mid+1 , r);
}
public int[] sortArray(int[] nums) {
quickSort(nums, 0, nums.length-1);
return nums;
}
}
二、分析快速排序的比较次数
假设我们现在有n个元素。我们就来分析最好情况下快排,即每次区间都能达到二分效果。
假设当前区间长度为L,那么一趟快排比较次数是L(与枢轴相比)。递归进行后,我们得到长度为L/2的两个区间,这两个区间的比较次数各自为L/2。
明白了吧。从区间长度出发,n长度区间有1个,n/2长度区间有2个,…
n
/
2
k
n/2^k
n/2k 长度区间有
2
k
2^k
2k个。
于是所有比较次数就是所有不同长度区间比较之和,有一个规律,就是 n / 2 k ∗ 2 k = n n/2^k *2^k = n n/2k∗2k=n, 相同长度区间总的比较次数都是n。
那么有多少个不同长度区间呢?很简单,二分下去,就可以得到 logn
所以我们简单得到快排时间复杂度为 O(nlogn)
三、更直观一点
以F(n)表示长度为n的区间比较次数,我们可以得到:
F ( n ) = n + 2 F ( n / 2 ) = n + 2 ( n / 2 + 2 ( F ( n / 4 ) ) ) = 2 n + 4 F ( n / 4 ) F(n) = n+2F(n/2) =n+2(n/2 +2(F(n/4)))=2n+4F(n/4) F(n)=n+2F(n/2)=n+2(n/2+2(F(n/4)))=2n+4F(n/4)
不难看出:
F ( n ) = k ∗ n + 2 k F ( n / 2 k ) F(n) = k*n +2^kF(n/2^k) F(n)=k∗n+2kF(n/2k)
当k为 l o g 2 n log_2^n log2n 时, F ( n ) = n l o g 2 n + n F ( 1 ) F(n) = nlog_2^n +nF(1) F(n)=nlog2n+nF(1) ,F(1)为0,因此 F ( n ) = n l o g 2 n F(n) = nlog_2^n F(n)=nlog2n