一、什么是快速排序?
每一轮排序选择一个基准点(pivot)进行分区
让小于基准点的元素进入一个分区,大于基准点的元素进入另一个分区
当分区完成时,基准点元素的位置就是其最终位置
在子分区内重复以上过程,直至子分区的元素个数小于等于1,这体现的是分而治之的思想(divide-and-conquer)
二、实现方式:单边循环快排(lomuto洛穆托分区方案)
选择最右元素作为基准点元素
j指针负责找到比基准点小的元素,一旦找到则与i进行交换
i指针维护小于基准点元素的边界,也是每次交换的目标索引
最后基准点与i交换,i即为分区位置
代码如下:
import java.util.Arrays;
public class QuickSort1 {
public static void main(String[] args) {
int[] a ={5,3,7,2,9,8,1,4};
quick(a,0,a.length-1);
}
//递归实现快排
public static void quick(int[] a,int low,int high){
if(low>=high){
return;
}
int p = partition(a, low, high);//p 索引值
quick(a,low,p-1);
quick(a,p+1,high);
}
//分区方法
public static int partition(int[] a, int low, int high) {
// 返回值元素代表了基准点元素所在的正确索引,用它确定下一轮分区的边界
int pv = a[high];
int i = low;
for (int j = low; j < high; j++) {
if (a[j] < pv) {//如果找到比基准点元素小的元素
swap(a, i, j);
i++;
}
}
swap(a, high, i);
System.out.println(Arrays.toString(a));
return i;
}
public static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
结果及过程:
小优化点:分区方法内,如果找到比基准点元素小的元素,如果i不等于j时再交换,最后交换基准点时,如果i不等于最后一个元素位置时再交换
public static int partition(int[] a, int low, int high) {
// 返回值元素代表了基准点元素所在的正确索引,用它确定下一轮分区的边界
int pv = a[high];
int i = low;
for (int j = low; j < high; j++) {
if (a[j] < pv) {//如果找到比基准点元素小的元素
if(i!=j) {
swap(a, i, j);
}
i++;
}
}
if(i!=high){
swap(a, high, i);
}
System.out.println(Arrays.toString(a));
return i;
}
三、实现方式:双边循环快排(并不完全等价于hoare霍尔分区方案)
选择最左元素作为基准点元素
j指针负责从右向左找比基准点小的元素,i指针负责从左向右找比基准点大的元素,一旦找到二者交换,直至i,j相交
最后基准点与i(此时i与j相等)交换,i即为分区位置
代码如下:
import java.util.Arrays;
public class QuickSort2 {
public static void main(String[] args) {
int[] a = {5, 3, 7, 2, 9, 8, 1, 4};
quick(a, 0, a.length - 1);
}
//递归实现快排
public static void quick(int[] a, int low, int high) {
if(low>=high){
return;
}
int p = partition(a, low, high);//p 索引值
quick(a,low,p-1);
quick(a,p+1,high);
}
//分区方法
public static int partition(int[] a, int low, int high) {
int pv = a[low];
int i = low;
int j = high;
while (i < j) {
//顺序:要先从右往左找小的,再从左往右找大的
while (j > i && a[j] > pv) {
j--;
}
while ((i < j && a[i] <= pv)) {
i++;
}
swap(a,i,j);
}
swap(a,low,j);
System.out.println(Arrays.toString(a));
return j;
}
public static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
结果如图:
四、快速排序-特点
平均时间复杂度是O(nlog2n),最坏时间复杂度O(n2)
数据量较大时,优势非常明显
属于不稳定排序,遇到相同值的元素可能交换其位置