1. 思路
每次以末尾数字为基数,比它大的放右边,小的放左边,全排完就好了。
2. 过程
左右划分,共logN次,每部分以最右边为基准再划分 小于基准 等于基准 大于基准的部分,
返回【和基准相等的数a1,和基准相等的数a2】,此时这部分的数就排好了,左右再划分剩下的,所有小的、所有大的
3. 代码
public void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
int N = arr.length;
//随机一个数和末尾数交换
swap(arr, (int) (Math.random() * (N)), N - 1);
//全范围迭代
int[] equalsArea = neitherlandsFlag(arr, 0, N - 1);
//获取当前基准的左部分和有部分边界值(包含)
int leftArea = equalsArea[0];
int rightArea = equalsArea[1];
Stack<Op> stack = new Stack();
//左右分别迭代
stack.push(new Op(0, leftArea - 1));
stack.push(new Op(rightArea + 1, N - 1));
while (!stack.isEmpty()) {
Op op = stack.pop();
if (op.left < op.right) {
//如果左边小于右边,继续迭代
swap(arr, (int) (op.left + (Math.random() * (op.right - op.left + 1))), op.right);
//在当前子范围继续拆分左右部分
equalsArea = neitherlandsFlag(arr, op.left, op.right);
leftArea = equalsArea[0];
rightArea = equalsArea[1];
stack.push(new Op(op.left, leftArea-1));
stack.push(new Op(rightArea+1, op.right));
}
}
}
class Op{
int left;
int right;
Op(int left, int right) {
this.left = left;
this.right = right;
}
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static int[] neitherlandsFlag(int[] arr, int L, int R) {
if (L > R) {
return new int[]{-1, -1};
}
if (L == R) {
return new int[]{L, L};
}
//小于基准数的左边界
int less = L - 1;
//大于基准数的右边界
int more = R;
int cur = L;
while (cur < more) {
if (arr[cur] == arr[R]) {
//如果当前数和基准数相同
cur++;
} else if (arr[cur] < arr[R]) {
//当前数比基准数小
swap(arr, less + 1, cur);
less++;
cur++;
} else if (arr[cur] > arr[R]) {
more--;
swap(arr, cur, more);
}
}
//交换基准数和 大于基准数的最小边界值
swap(arr, more, R);
return new int[]{less + 1, more};
}