数据结构|排序(二)(快速排序)
作者:互联网
8. 快速排序
8.1 原理
- 从待排序区间选择一个数,作为基准值(pivot);
- Partition:遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边(不要求任何顺序),将比基准值大的(可以包含相等的)放到基准值的右边;
- 采用分治思想,对左右两个小区间按照相同的方法处理,直到小区间的长度 == 1,代表已经有序,或者小区间的长度 == 0,代表没有数据。
8.2 实现
public static void quickSort(long[] array) {
quickSortRange(array, 0, array.length - 1);
}
private static void quickSortRange(long[] array, int from, int to) {
int size = to - from + 1;
// 3. 直到,待排序区间的元素个数 <= 1
if (size <= 1) {
return;
}
// 1. 选择基准值 array[from]
// 2. 做 partition,返回基准值跑到哪里去了 [pivotIdx]
int pivotIdx = partition(array, from, to);
// 左边的区间表示:[from, pivotIdx - 1]
// 右边的区间表示:[pivotIdx + 1, to]
// 3. 分别对左右两个小区间按照相同的方式处理(递归调用)
quickSortRange(array, from, pivotIdx - 1);
quickSortRange(array, pivotIdx + 1, to);
}
8.3 Partition过程
Hoare法
private static int partition1(long[] array, int from, int to) {
long pivot = array[from];
int left = from;
int right = to;
// 只要还有未比较的元素,循环就得继续
// (left, right] 的元素个数 right - left > 0
while (left < right) {
// 因为我们基准值在左边,所以先走右边
while (left < right && array[right] >= pivot) {
right--;
}
while (left < right && array[left] <= pivot) {
left++;
}
long t = array[left];
array[left] = array[right];
array[right] = t;
}
long t = array[from];
array[from] = array[left];
array[left] = t;
return left;
}
挖坑法
基本思路和Hoare法一致,只是不再进行交换,而是进行赋值(填坑+挖坑)
private static int partition2(long[] array, int from, int to) {
long pivot = array[from];
int left = from;
int right = to;
while (left < right) {
while (left < right && array[right] >= pivot) {
right--;
}
array[left] = array[right];
while (left < right && array[left] <= pivot) {
left++;
}
array[right] = array[left];
}
array[left] = pivot;
return left;
}
前后遍历法
private static int partition3(long[] array, int from, int to) {
long pivot = array[from];
int d = from + 1;
for (int i = from + 1; i <= to; i++) {
if (array[i] < pivot) {
long t = array[d];
array[d] = array[i];
array[i] = t;
d++;
}
}
long t = array[from];
array[from] = array[d - 1];
array[d - 1] = t;
return d - 1;
}
8.4 性能分析
时间复杂度:
最好的情况:o(n * log(n)),完全二叉树
最坏的情况:o(n ^ 2),单支树
平均:o(n * log(n))
空间复杂度:
一次partition的空间复杂度o(1),递归调用时栈帧需要消耗空间,影响其的是二叉树的高度。
最好的情况:o(log(n))
平均:o(log(n))
最坏:o(n)
稳定性:不具备稳定性
8.5 如何进行快速排序优化
-
基准值的选择
(1) 随机选择 --> 使得选到最坏情况的概率降低
(2) 三数取中 --> 选择第一个数,最后一个数,中间数,这三个数中大小是中值的数作为基准值,选出基准值后,重新放到最左边进行partition -
做partition的时,等于基准值的元素分离出来
[< pivot] [== pivot] [> pivot] -
当待排序区间的元素个数小于阈值,用插排代替快排
-
非递归 --> 递归
-
双基准值选择
pivot1 < pivot2
[< pivot1] [== pivot1] [> pivot1 && < pivot2] [== pivot2] [> pivot2]
标签:数据结构,基准值,int,long,right,array,排序,快速,left 来源: https://blog.csdn.net/Yang_ccH/article/details/122639937