快排
基本方法
通过一趟排序,将数据分割成独立的两部分,一部分数据均小于另一部分数据,再分别对两部分数据排序,以此递归,实现数据有序。
算法实现
let swap = (arr,i,j)=>{
[arr[i],arr[j]] = [arr[j], arr[i]];
}
//将第一位作为基准,将小于基准的数移到左边
let partition = (arr,left,right) => {
let pivot = arr[left];
let i = left;
let j = left + 1;
while(j <= right){
if(arr[j] < pivot){
i++;
swap(arr,i,j);
}
j++;
}
//以i为划分点
swap(arr,i,left);
return i;
}
let quick = (arr,left,right) =>{
//排序已完成
if(left >= right){
return arr;
}
//找到划分中点
let mid = partition(arr,left,right);
//左右区域递归划分
quick(arr,left,mid-1);
quick(arr,mid+1,right);
return arr;
}
复杂度分析
性能最优的情况
如果每一次pivot
的取值都是待排序数据的中间值
(每次都划分为2个均匀子区间
),则每一次partition需要对整个数组扫描,后对均分的数组再次进行扫描,即n + 2T(n/2)
,可以推出:
T(n) <= n + 2T(n/2)
T(n) <= n + 2( 2T(n/4) + n/2 ) = 2n + 4T(n/4)
T(n) <= 2n + 4( 2T(n/8) + n/4) = 3n + 8T(n/8)
...
T(n) <= nT(1) + nlogn
即最优时间复杂度为O(nlogn)
;例如[3,2,1,5,4]
最差的情况
待排序数据为逆序,每次划分得到的是减少一个数据的子区间
,则每次的比较次数为从n-1累加至1,即n(n-1)/2
,时间复杂度为O(n**2)
; 例如[5,4,3,2,1]