快速排序由于排序效率在同为 O(nlogn) 的几种排序方法中效率最高,因此经常被采用
package com.yanheng.common;
public class QuickSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
// int[] array = new int[] {11,34,57,87,12,46,69,135,765,23};
// int[] array = {6, 4, 3, 2, 7, 9, 1, 8, 5};
int[] array = new int[] {11,34,57,87,12,46,69,135,765,23};
quickSortMain(array, 0, array.length-1);
for(int i = 0; i < array.length;i++) {
System.out.println(array[i]);
}
}
public static int quickSortSub(int[] array, int start,int end ){
// start作为基数进行排序
// int low = start;
int temp = array[start];
// int high = end ;
while(start < end) {// 确保左边小于右边
// 从右向左与基数比较,小于基数则向左移动
while(array[end] >= temp && start < end) {
end--;
}
if(start < end) {
array[start] = array[end];
start++;
}
while(array[start] <= temp && start < end) {
start++;
}
if(start < end) {
array[end] = array[start];
end--;
}
}
array[start] = temp;
return start ;
}
public static void quickSortMain(int[] array, int left, int right) {
if(array == null || left >= right || array.length <=1) {
return ;
}
int mid = quickSortSub(array, left, right);
quickSortMain(array, left, mid);
quickSortMain(array, mid+1, right);
}
}
我们不妨尝试来对这个算法进行一下时间复杂度的分析:
-
最好情况
在最好的情况下,每次我们进行一次分区,我们会把一个序列刚好分为几近相等的两个子序列,这个情况也我们每次递归调用的是时候也就刚好处理一半大小的子序列。这看起来其实就是一个完全二叉树,树的深度为 O(logn),所以我们需要做 O(logn) 次嵌套调用。但是在同一层次结构的两个程序调用中,不会处理为原来数列的相同部分。因此,程序调用的每一层次结构总共全部需要 O(n) 的时间。所以这个算法在最好情况下的时间复杂度为 O(nlogn)。
事实上,我们并不需要如此精确的分区:即使我们每个基准值把元素分开为 99% 在一边和 1% 在另一边。调用的深度仍然限制在 100logn,所以全部运行时间依然是 O(nlogn)。
-
最坏情况
事实上,我们总不能保证上面的理想情况。试想一下,假设每次分区后都出现子序列的长度一个为 1 一个为 n-1,那真是糟糕透顶。这一定会导致我们的表达式变成:
T(n) = O(n) + T(1) + T(n-1) = O(n) + T(n-1)
这和插入排序和选择排序的关系式真是如出一辙,所以我们的最坏情况是 O(n²)。
-
基准数选择
-
固定基准数
上面的那种算法,就是一种固定基准数的方式。如果输入的序列是随机的,处理时间还相对比较能接受。但如果数组已经有序,用上面的方式显然非常不好,因为每次划分都只能使待排序序列长度减一。这真是糟糕透了,快排沦为冒泡排序,时间复杂度为 O(n²)。因此,使用第一个元素作为基准数是非常糟糕的,我们应该立即放弃这种想法。
-
随机基准数
这是一种相对安全的策略。由于基准数的位置是随机的,那么产生的分割也不会总是出现劣质的分割。但在数组所有数字完全相等的时候,仍然会是最坏情况。实际上,随机化快速排序得到理论最坏情况的可能性仅为1/(2^n)。所以随机化快速排序可以对于绝大多数输入数据达到 O(nlogn) 的期望时间复杂度。
-
三数取中
虽然随机基准数方法选取方式减少了出现不好分割的几率,但是最坏情况下还是 O(n²)。为了缓解这个尴尬的气氛,就引入了「三数取中」这样的基准数选取方式。
-
https://blog.csdn.net/u012562943/article/details/100136531?utm_source=app