1.原理
1.从待排序区间选择一个数,作为基准值(pivot);
2.partition(分割): 遍历整个待排序区间, 将比基准值小的(可包含相等的)放到基准值的左边, 将比基准值大的(可包含相等的)放到基准值的右边;
3.采用分治的思想, 对左右两个小区间按照同样的方式处理, 直到小区间的长度==1, 代表已经有序, 或者小区间的长度等于0, 代表没有数据.
2.代码实现
import java.util.*;
public class quickSort{
public static void quickSort(int[] array){
quickSortInternal(array, 0, array.length-1);
}
private static void quickSortInternal(int[] array, int left, int right){ //快排核心
//递归出口
if(left == right){ //待排序区间是[left,right]
return;
}
if(left > right){
return;
}
int pivotIndex = partition(array, left, right); //pivotIndex 代表基准值最终停留的下标
quickSortInternal(array, left, pivotIndex - 1); //[left, pivotIndex - 1] 都是小于等于基准值的
quickSortInternal(array, pivotIndex + 1, right); //[pivotIndex + 1, right] 都是大于等于基准值的
}
private static int partition(int[] array, int left, int right){ //hoare法
int i = left;
int j = right;
int pivot = array[left]; //选择最左边为基准值
while(i < j){
while(i < j && array[j] >= pivot){
j--;
}
while((i < j) && (array[i] <= pivot)){
i++;
}
swap(array, i, j);
}
swap(array, i, left); // 当i和j相遇的时候,交换i和left的值
return i;
}
private static void swap(int[] array, int a, int b){
int temp = array[a];
array[a] = array[b];
array[b] = temp;
}
public static void main(String[] args){ //打印测试
int[] array = {3,4,9,2,7,5,6,10};
quickSortInternal(array, 0, array.length - 1);
for(int i = 0; i <= array.length - 1; i++){
System.out.print(array[i]+" ");
}
}
}
为什么要先让 j-- (让j先出动)?
如果选取最左边的数array[left]作为基准数, 那么先从右边开始可保证 i, j在相遇时, 相遇数是小于基准数的, 能保证相遇数(即最后交换的那个数)会小于等于最左边那个数(基准数).
如果选取最右边的数为基准数,那么就从最左边开始, 即先进行 i++
在待排序区间选择一个基准值,有哪几种方法方法
1. 选择左边或者右边
2. 随机选取
3. 几数取中法
3.性能
时间复杂度 最好 O(nlog(n))
平均 O(nlog(n))
最差 O(n^2)
空间复杂度 最好 O(log(n))
平均 O(log(n))
最差 O(n)
不稳定