快速排序思想 以及 递归与非递归实现(含对数器,详细注释)

基本思想:

小于等于的放左边,大于的放右边,p在中间,p为数组最右一个数,小于等于区初始为-1

实现逻辑:

  1. 当前数 <=p,当前数 和 小于等于区 的 后一个数 进行交换,小于等于区 外扩,当前数 跳下一个
  2. 当前数 >p,当前数 直接跳下一个
  3. 遍历到数组末尾停止

进阶思想:

小于的放左边,大于的放右边,等于p的在中间,p为最右一个数,小于区的初始为-1,大于区初始为 a.length-1

实现逻辑:

  1. 当前数 <p,当前数 和 小于区 的 后一个数 进行交换,小于区外扩,当前数 跳下一个
  2. 当前数 >p,当前数 和 大于区 的 前一个数 进行交换,大于区外扩,当前数 不动
  3. 当 当前数 撞上 大于区 的边界时,大于区 的 第一个数 和 最后一个数 进行交换,停止
    快排

递归代码实现(进阶思想)

// 递归写法
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!");

	}

}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从前慢慢慢死了

打钱!一分也行啊!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值