整体结构
/**
* 快速排序
*
* @author 小流慢影
* @date 2023年3月16日
*/
public class Quicksort {
public static void main(String[] args) {
int[] array = {5, 4, 3, 1, 2, 13, 12, 10, 11, 9, 7, 8, 6, 3, 5};
System.out.println("原数组:" + Arrays.toString(array));
quicksort(array, 0, array.length - 1);
System.out.println("排序后数组:" + Arrays.toString(array));
}
public static void quicksort(int[] array, int startIndex, int endIndex) {
if (startIndex >= endIndex) {
return;
}
// 具体排序,返回中心点(pivot)下标,下面单独展示具体排序算法
int pivotIndex = specificSort(array, startIndex, endIndex);
// 对中心点左端的数组进行递归排序
quicksort(array, startIndex, pivotIndex - 1);
// 对中心点右端的数组进行递归排序
quicksort(array, pivotIndex + 1, endIndex);
}
}
具体排序算法
双指针-交换法
/**
* 具体排序
* 本方法采用 双指针-交换法
*
* @param array 待排数组
* @param startIndex 开始下标
* @param endIndex 结束下标
* @return 中心点(pivot)下标
*/
private static int specificSort(int[] array, int startIndex, int endIndex) {
/*
* 这里将最左边位置设为中心点
* 如果将最左边的作为起始点,则下面循环一定要右侧先走,否则会出现循环完毕后,左右互换点的值大于中心点,然后又被置换到最左侧了,引起排序异常
* 同理,如果将最右边的作为起始点,则下面循环一定要左侧先走;
*/
int pivot = array[startIndex];
int leftPointer = startIndex;
int rightPointer = endIndex;
while (leftPointer < rightPointer) {
// 因为上面是将最左边位置设为了中心点,所以右侧先走
while (leftPointer < rightPointer && array[rightPointer] >= pivot) {
rightPointer--;
}
while (leftPointer < rightPointer && array[leftPointer] <= pivot) {
leftPointer++;
}
// 左右互换
if (leftPointer < rightPointer) {
int temp = array[leftPointer];
array[leftPointer] = array[rightPointer];
array[rightPointer] = temp;
}
}
// 左右指针相等时,将pivot换到这个位置来
array[startIndex] = array[leftPointer];
array[leftPointer] = pivot;
return leftPointer;
}
双指针-挖坑法
/**
* 具体排序
* 本方法采用 双指针-挖坑法
*
* @param array 待排数组
* @param startIndex 开始下标
* @param endIndex 结束下标
* @return 中心点(pivot)下标
*/
private static int specificSort(int[] array, int startIndex, int endIndex) {
// 这里将最左边的值设为中心点,同时,也创建了一个“坑”,后面的值可以直接填在这个“坑”里
int pivot = array[startIndex];
int leftPointer = startIndex;
int rightPointer = endIndex;
while (leftPointer < rightPointer) {
// 从最右边开始,直到找到小于中间点的位置
while (leftPointer < rightPointer && array[rightPointer] >= pivot) {
rightPointer--;
}
if (leftPointer < rightPointer) {
// 第一次到这里时,会把第一次右边扫到的值,放到最左边的“坑”中,此时,最右边留下了“坑”
array[leftPointer] = array[rightPointer];
leftPointer++;
}
// 左边开始找,直到找到大于中间点的位置
while (leftPointer < rightPointer && array[leftPointer] <= pivot) {
leftPointer++;
}
if (leftPointer < rightPointer) {
// 将这个大于中间点的位置的值放到上面右边留下的“坑”
array[rightPointer] = array[leftPointer];
rightPointer--;
}
}
// 上面循环结束后,必然leftPointer = rightPointer,因为循环最后一步在这个重合位置留了“坑”,所以将中心点放进去
array[rightPointer] = pivot;
return rightPointer;
}
单指针
/**
* 具体排序
* 本方法采用 单指针
*
* @param array 待排数组
* @param startIndex 开始下标
* @param endIndex 结束下标
* @return 中心点(pivot)下标
*/
private static int specificSort(int[] array, int startIndex, int endIndex) {
// 将最左边的设置为中心点
int pivot = array[startIndex];
// 单指针从最左边开始
int singlePointer = startIndex;
// 遍历从开始位置的下一个开始,到最后位置结束
for (int i = startIndex + 1; i <= endIndex; i++) {
/*
* 一旦遍历的位置的值小于中心点,则指针右移。
* i是会大于等于singlePointer的,当array[i]的值大于中心点时,不会变,i会在循环后增加。
* 所以当i>singlePointer时,singlePointer后面一位必然是大于中心点的。
* 所以当i的位置的值小于中心点时,则可以和singlePointer后面一位的值交换。
*/
if (array[i] < pivot) {
singlePointer++;
if (i != singlePointer) {
int temp = array[singlePointer];
array[singlePointer] = array[i];
array[i] = temp;
}
}
}
// 一轮循环后,将中心点与最后的singlePointer位置交换,能保证singlePointer之后的值都是大于中心点的,同时,左边都是小于中心点的
array[startIndex] = array[singlePointer];
array[singlePointer] = pivot;
return singlePointer;
}