文字描述:
1、每一轮排序选择一个基准点(pivot
)进行分区
(1)让小于基准点的元素的进入一个分区,大于基准点的元素进入另一个分区
(2)当分区完成后时,基准点元素的位置就是其最终位置
2、在子分区内重复以上过程,直至子分区元素个数少于等于 1,这体现的是分而治之的思想(divide-and-conquer
)
实现方式:
1、单边循环快排
(1)选择最右元素作为基准点元素
(2)j 指针负责找到比基准点小的元素,一旦找到则与 i 进行交换
(3)i 指针维护小于基准点元素的边界,也就是每次交换的目标索引
(4)最后基准点与 i 交换,i 即为分区位置
2、双边循环快排
(1)选择最左元素作为基准点元素
(2)j 指针负责从右向左找比基准点小的元素,i 指针负责从左向右找比基准点大的元素,一旦找到二者交换,直至 i,j 相交
(3)最后基准点与 i(此时 i 与 j 相等)交换,i 即为分区位置
代码
单边循环
public class QuickSortDemo {
public static void main(String[] args) {
int[] array = {
5, 9, 7, 4, 1, 3, 2, 8};
quickSort(array);
System.out.println(Arrays.toString(array));
}
/**
* 快排单边循环
* 以最右边的元素为基准值
* i 负责维护分区的边界,j 负责从左至右找比基准值大的
* 与 i 交换,最后 i 所在的位置就是基准值要去的位置
* 然后一直分区重复步骤
* 结束条件:分区里的元素 <= 1
*/
public static void quickSort(int[] array, int l, int h) {
if (l >= h) {
return ;
}
// 以分区最右边的元素为基准点
int pv = array[h];
// i 维护分区的边界,i 左边比基准值小,右边比基准值大
int i = l;
for (int j = l; j < h; j++) {
if (array[j] < pv) {
if (i != j) {
swap(array, i, j);
}
i++;
}
}
// i 的位置就是基准点要去的位置
if (i != h) {
swap(array, i, h);
}
// 进行递归
quickSort(array, l, i - 1);
quickSort(array, i + 1, h);
}
public static void quickSort(int[] array) {
quickSort(array, 0, array.length - 1);
}
/**
* 交换数组中的两个元素
*/
public static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
双边循环
/**
* 快排双边循环
* 以最左边的元素为基准值
* i 从左至右找比基准值大的
* j 从左至右找比基准值小的
* i, j 交换
* 最后 i 或 j 就是基准值要去的位置
*/
public static void quickSort(int[] array, int l, int h) {
if (l >= h) {
return ;
}
// 以最左边的元素为基准值
int pv = array[l];
int i = l;
int j = h;
while (i < j) {
// 先 j 后 i,位置不能颠倒
while (i < j && array[j] > pv) {
j--;
}
// array[i] <= pv,第一次 i == l 的,会把基准值交换走
while (i < j && array[i] <= pv) {
i++;
}
swap(array, i, j);
}
// 交换元素
swap(array, i, l);
quickSort1(array, l, i - 1);
quickSort1(array, i + 1, h);
}