给定一个数组arr,和一个整数num,请把小于等于num的数放在数组的左边,大于num的数放在数组的右边,要求额外空间复杂度O(1),时间复杂度O(N)
public static int partition(int[] arr, int L, int R) { if (L > R) { return -1; } if (L == R) { return L; } int lessEqual = L - 1; int index = L; while (index < R) { if (arr[index] <= arr[R]) { swap(arr, index, ++lessEqual); } index++; } swap(arr, ++lessEqual, R); return lessEqual; }
荷兰国旗问题:
给定一个数组arr,和一个整数num,请把小于num的数放在数组的左边,等于num的数放在中间,大于num的数放在数组的右边,要求额外空间复杂度O(1),时间复杂度O(N)
public static int[] netherlandsFlag(int[] arr, int L, int R) { if (L > R) { // L...R L>R return new int[] { -1, -1 }; } if (L == R) { return new int[] { L, R }; } // < 区 右边界 int less = L - 1; // > 区 左边界 int more = R; int index = L; while (index < more) { if (arr[index] == arr[R]) { index++; } else if (arr[index] < arr[R]) { swap(arr, index++, ++less); } else { // > swap(arr, index, --more); } } swap(arr, more, R); // <[R] =[R] >[R] return new int[] { less + 1, more }; }
在arr[L..R]范围上,进行快速排序的过程:
1)用arr[R]对该范围做partition,<= arr[R]的数在左部分并且保证arr[R]最后来到左部分的最后一个位置,记为M; <= arr[R]的数在右部分(arr[M+1..R])
2)对arr[L..M-1]进行快速排序(递归)
3)对arr[M+1..R]进行快速排序(递归) 因为每一次partition都会搞定一个数的位置且不会再变动,所以排序能完成
public static void quickSort1(int[] arr) { if (arr == null || arr.length < 2) { return; } process1(arr, 0, arr.length - 1); } public static void process1(int[] arr, int L, int R) { if (L >= R) { return; } // L..R partition arr[R] [ <=arr[R] arr[R] >arr[R] ] int M = partition(arr, L, R); process1(arr, L, M - 1); process1(arr, M + 1, R); }
在arr[L..R]范围上,进行快速排序的过程:
1)用arr[R]对该范围做partition,< arr[R]的数在左部分,== arr[R]的数中间,>arr[R]的数在右部分。假设== arr[R]的数所在范围是[a,b]
2)对arr[L..a-1]进行快速排序(递归)
3)对arr[b+1..R]进行快速排序(递归) 因为每一次partition都会搞定一批数的位置且不会再变动,所以排序能完成
public static void quickSort2(int[] arr) { if (arr == null || arr.length < 2) { return; } process2(arr, 0, arr.length - 1); } public static void process2(int[] arr, int L, int R) { if (L >= R) { return; } // [ equalArea[0] , equalArea[0]] int[] equalArea = netherlandsFlag(arr, L, R); process2(arr, L, equalArea[0] - 1); process2(arr, equalArea[1] + 1, R); }
在arr[L..R]范围上,进行快速排序的过程:
1)在这个范围上,随机选一个数记为num,用num对该范围做partition,< num的数在左部分,== num的数中间,>num的数在右部分。假设== num的数所在范围是[a,b]
2)对arr[L..a-1]进行快速排序(递归)
3)对arr[b+1..R]进行快速排序(递归) 因为每一次partition都会搞定一批数的位置且不会再变动,所以排序能完成
public static void quickSort3(int[] arr) { if (arr == null || arr.length < 2) { return; } process3(arr, 0, arr.length - 1); } public static void process3(int[] arr, int L, int R) { if (L >= R) { return; } swap(arr, L + (int) (Math.random() * (R - L + 1)), R); int[] equalArea = netherlandsFlag(arr, L, R); process3(arr, L, equalArea[0] - 1); process3(arr, equalArea[1] + 1, R); }
递归和非递归两种方式写出随机快排
// 快排递归版本 public static void quickSort1(int[] arr) { if (arr == null || arr.length < 2) { return; } process(arr, 0, arr.length - 1); } public static void process(int[] arr, int L, int R) { if (L >= R) { return; } swap(arr, L + (int) (Math.random() * (R - L + 1)), R); int[] equalArea = netherlandsFlag(arr, L, R); process(arr, L, equalArea[0] - 1); process(arr, equalArea[1] + 1, R); }
public static class Op { public int l; public int r; public Op(int left, int right) { l = left; r = right; } } // 快排非递归版本 public static void quickSort2(int[] arr) { if (arr == null || arr.length < 2) { return; } int N = arr.length; swap(arr, (int) (Math.random() * N), N - 1); int[] equalArea = netherlandsFlag(arr, 0, N - 1); int el = equalArea[0]; int er = equalArea[1]; Stack<Op> stack = new Stack<>(); stack.push(new Op(0, el - 1)); stack.push(new Op(er + 1, N - 1)); while (!stack.isEmpty()) { Op op = stack.pop(); // op.l ... op.r if (op.l < op.r) { swap(arr, op.l + (int) (Math.random() * (op.r - op.l + 1)), op.r); equalArea = netherlandsFlag(arr, op.l, op.r); el = equalArea[0]; er = equalArea[1]; stack.push(new Op(op.l, el - 1)); stack.push(new Op(er + 1, op.r)); } } }