基本思想:
小于等于的放左边,大于的放右边,p在中间,p为数组最右一个数,小于等于区初始为-1
实现逻辑:
- 当前数 <=p,当前数 和 小于等于区 的 后一个数 进行交换,小于等于区 外扩,当前数 跳下一个
- 当前数 >p,当前数 直接跳下一个
- 遍历到数组末尾停止
进阶思想:
小于的放左边,大于的放右边,等于p的在中间,p为最右一个数,小于区的初始为-1,大于区初始为 a.length-1
实现逻辑:
- 当前数 <p,当前数 和 小于区 的 后一个数 进行交换,小于区外扩,当前数 跳下一个
- 当前数 >p,当前数 和 大于区 的 前一个数 进行交换,大于区外扩,当前数 不动
- 当 当前数 撞上 大于区 的边界时,大于区 的 第一个数 和 最后一个数 进行交换,停止
快排
递归代码实现(进阶思想)
// 递归写法
public static void quickSort(int[] a) {
/**
* 快排思想:不断分区,每次中枢的位置一定是确定的
*/
// 对 [r,l] 区间进行排序
process(a,0,a.length-1);
}
// 大于p的放在右边 小于p的放在左边 等于p的放在中间
public static void process(int[] a, int l, int r){
// 递归出口
if(r-l < 1) return;
int[] eqLR = partition(a,l,r);
process(a, l,eqLR[0]-1);
process(a,eqLR[1]+1, r);
}
public static int[] partition(int[] a, int l, int r){
// 选取最右侧为中枢
int p = a[r];
// 小于区域
int less = l - 1;
// 大于区域
int more = r;
// 当前位置
int index = l;
// 当前值撞到大于区停止
while (index < more) {
// 如果当前值小于p
if(a[index] < p) {
// 当前值和小于区的右一个值进行交换, 当前值右移
swap(a, ++less, index++);
} else if (a[index] > p) {
// 当前值和大于区左一个值进行交换,当前值不变
swap(a,--more, index);
} else {
// 相等直接前移
index++;
}
}
// 交换大于区的首位
swap(a, more, r);
// 返回等于区域的边界 注意: 大于区的第一个就是等于区的边界
return new int[]{less+1,more};
}
// 交换位置
private static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
非递归代码实现 (进阶思想)
// 辅助类
static class Op {
// 用来记录在什么范围进行排序
int l;
int r;
public Op(int l, int r) {
this.l = l;
this.r = r;
}
}
// 非递归主体程序
public static void quickSort2(int[] a) {
int N = a.length;
Stack<Op> stack = new Stack<>();
stack.push(new Op(0,N-1));
while (!stack.isEmpty()) {
Op task = stack.pop();
// 保证取出来的任务可用
if (task.l < task.r){
int[] eqArea = partition(a, task.l, task.r);
stack.push(new Op(task.l,eqArea[0]-1));
stack.push(new Op(eqArea[1] + 1, task.r));
}
}
}
含对数器的完整代码(可运行)
package class05;
import java.util.Arrays;
import java.util.Stack;
public class My_PartitionAndQuickSort {
public static void quickSort(int[] a) {
/**
* 快排思想:不断分区,每次中枢的位置一定是确定的
*/
// 对 [r,l] 区间进行排序
process(a,0,a.length-1);
}
// 大于p的放在右边 小于p的放在左边 等于p的放在中间
public static void process(int[] a, int l, int r){
// 递归出口
if(r-l < 1) return;
int[] eqLR = partition(a,l,r);
process(a, l,eqLR[0]-1);
process(a,eqLR[1]+1, r);
}
public static int[] partition(int[] a, int l, int r){
// 选取最右侧为中枢
int p = a[r];
// 小于区域
int less = l - 1;
// 大于区域
int more = r;
// 当前位置
int index = l;
// 当前值撞到大于区停止
while (index < more) {
// 如果当前值小于p
if(a[index] < p) {
// 当前值和小于区的右一个值进行交换, 当前值右移
swap(a, ++less, index++);
} else if (a[index] > p) {
// 当前值和大于区左一个值进行交换,当前值不变
swap(a,--more, index);
} else {
// 相等直接前移
index++;
}
}
// 交换大于区的首位
swap(a, more, r);
// 返回等于区域的边界 注意: 大于区的第一个就是等于区的边界
return new int[]{less+1,more};
}
// 交换位置
private static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
// 快速排序非递归版本
// 辅助类
static class Op {
// 用来记录在什么范围进行排序
int l;
int r;
public Op(int l, int r) {
this.l = l;
this.r = r;
}
}
// 非递归主体程序
public static void quickSort2(int[] a) {
int N = a.length;
Stack<Op> stack = new Stack<>();
stack.push(new Op(0,N-1));
while (!stack.isEmpty()) {
Op task = stack.pop();
// 保证取出来的任务可用
if (task.l < task.r){
int[] eqArea = partition(a, task.l, task.r);
stack.push(new Op(task.l,eqArea[0]-1));
stack.push(new Op(eqArea[1] + 1, task.r));
}
}
}
// for test
public static int[] generateRandomArray(int maxSize, int maxValue) {
int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
}
return arr;
}
// for test
public static int[] copyArray(int[] arr) {
if (arr == null) {
return null;
}
int[] res = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
res[i] = arr[i];
}
return res;
}
// for test
public static boolean isEqual(int[] arr1, int[] arr2) {
if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
return false;
}
if (arr1 == null && arr2 == null) {
return true;
}
if (arr1.length != arr2.length) {
return false;
}
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
// for test
public static void printArray(int[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
// for test
public static void main(String[] args) {
int testTime = 500000;
int maxSize = 100;
int maxValue = 100;
boolean succeed = true;
for (int i = 0; i < testTime; i++) {
int[] arr1 = generateRandomArray(maxSize, maxValue);
int[] arr2 = copyArray(arr1);
int[] arr3 = copyArray(arr1);
// 递归版本
quickSort2(arr1);
// 非递归
// quickSort(arr1);
Arrays.sort(arr2);
if (!isEqual(arr1, arr2)) {
succeed = false;
break;
}
}
System.out.println(succeed ? "Nice!" : "Oops!");
}
}