快排本质上也是交换排序。不过对比交换排序的只能一直替换相邻元素的费劲。快排使用双向检索交换。好久不写,漏洞百出。常见的数组下标越界问题。
package xyz.cglzwz.question_bank;
public class QuickSort {
public static void main(String[] args) {
int[] s = new int[] {0, 2, 3, 9, 1};
quickSort(s, 0, s.length-1);
for (int x : s) {
System.out.println(x);
}
}
public static void quickSort(int[] a, int left, int right) {
// 必须先比较,不然分分钟下标越界
if (left >= right)
return;
int i = left;
int j = right;
// 取第一个数做轴枢
int pivot = a[left];
while (i < j) {
// 从右往左扫描,过滤比轴枢大的
while (i < j && a[j] >= pivot) j--;
//交换比枢轴小的记录到左端
a[i] = a[j];
// 从左往右扫描,过滤比轴枢小的
while (i < j && a[i] <= pivot) i++;
//交换比枢轴大的记录到右端
a[j] = a[i];
}
// 插入轴枢,此时 i = j
a[i] = pivot;
quickSort(a, left, i - 1);
quickSort(a, i + 1, right);
}
}
以上是正确运行的代码。之前一直把前面的声明和返回顺序写反了,如下
int i = left;
int j = right;
// 取第一个数做轴枢
int pivot = a[left];
if (left >= right)
return;
这样的问题是,如果选的轴枢如果是最小或者最大那个。一趟都没有交换。如果此时的i = j又原地踏步在索引0位置。那么0 - 1 = -1,到下一次递归的时候如果不提前判断left >= right就会下标异常了。
2. 交换理解
当然,本质是交换,写成上面那种不太像。下面的更容易理解
package xyz.cglzwz.question_bank;
public class QuickSort {
public static void main(String[] args) {
int[] s = new int[] {0, 2, 3, 9, 1};
quickSort(s, 0, s.length-1);
for (int x : s) {
System.out.println(x);
}
}
public static void quickSort(int[] a, int left, int right) {
// 必须先比较,不然分分钟下标越界
if (left >= right)
return;
int i = left;
int j = right;
// 取第一个数做轴枢
int pivot = a[left];
while (i < j) {
// 从右往左扫描,过滤比轴枢大的
while (i < j && a[j] >= pivot) j--;
// 从左往右扫描,过滤比轴枢小的
while (i < j && a[i] <= pivot) i++;
if (i < j) {
// 交换
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
// 交换目前轴枢位置和目的位置的值
a[left] = a[i];
// 目的位置插入轴枢,此时 i = j
a[i] = pivot;
quickSort(a, left, i - 1);
quickSort(a, i + 1, right);
}
}
此时跳出大while的时候,记得要把左边的轴枢索引和目的插入位置的数组元素作交换。因为对于第一种写法,这是差了这一步。