快速排序:20世纪最重要的算法之一,基于分治思想 O(nlogn),1s轻松完成百万数量级的排序
算法思路:从待排序的数组中选取任意一个元素[l…r],称为分区点(基准值)开始遍历过程,每当发现比基准值小的元素就放在基准值左边,每当发现>=基准值元素就放在基准值右边。
当结束一次遍历时,基准值元素一定在最终位置。
分区函数能否原地排序?O(1)
问题:当待排序元素近乎有序时,若选取的基准值恰好为最大值,此时分层退化成O(n),此时快排的时间复杂度退化为O(n^2) 最坏情况
最好情况:每次分区点的选择都恰好在中间位置,O(nlogn)
平均O(nlogn)
空间:O(1),原地排序
稳定性:不稳定算法(若基准值为最后一个元素,5 4 3 2 6 1 5)
扩展问题:如何在O(n)时间内找到一个无序数组的第K大元素?
分区点:
5 1 2 3 6 8 7
1 2 3 5 6 8 7
5 1 2 3 4 6 8 7
1 2 3 4 5 6 7 8
若k = 5
若array[i+1] = ,array[i] 就是第k大元素
若k > i+1 ,
n/2 + n/4 + n/8 +… + 1
快排优化:
1.当待排序的集合近乎有序时,由于默认选择的第一个元素作为基准值,会导致基准值划分的两个子数组严重不均衡,此时分层下来的结果近乎于n层,此时快排退化为复杂度为O(n^2)排序算法
解决:随机选取一个元素作为基准值,来降低每次都选到最小或最大值的概率
2.当待排序集合包含大量重复元素时,由于与基准值相等的元素个数过多,导致数组长度不均衡,此时分层下来的结果近乎n层,快排退化为O(n^2)
二路快排:
将大于和小于v的元素放在数组的两端,i索引不断向后扫描,当i的元素小于v时,i++;j索引不断向前扫描,当j的元素大于v时,j–;当i碰到一个>=v的元素以及j碰到一个<=v的元素,交换i与j的元素,i++,j–
快排:
分治:任意选取一个基准值,将所有比基准值放左边,比基准值大的放右边。一次过程下来,基准值到达最终位置。按照基准值左边与右边待排序数组重复上述过程
原地排序:默认选取第一个元素
优化1:随机选取一个基准值来避免分组造成的左右两个区间严重不均衡状态,造成分层趋向于O(n)层导致快排退化为O(n^2)
优化2:当待排序的数组中重复元素过多导致分组造成的左右两个区间严重不均衡状态,造成分层趋向于O(n)层导致快排退化为O(n^2)
双路快排:将重复元素交换位置来实现左右两个数组都有元素,避免分组不均衡的情况发生。
优化3:三路快排