排序算法之快速排序QuickSort(递归和非递归两种实现方式)

一、进行划分

快速排序的原理:按照数组中的一个数,将数组划分成为小于这个数、等于这个数,大于这个数三个部分从而进行排序。

首先我们定义一个partition方法,实现划分的功能:
定义L为数组的左边界,R为数组的右边界,把arr[R]作为划分值,
L初始值定义为数组 0 的位置,R初始值定义为数组最大索引(arr.length-1)。
定义一个小于区域最右边的位置lessR,初始值为-1
定义一个大于区域最左边的位置moreL,初始值为R(即最大索引位置)。
定义当前位置为index,初始值为0
index从第一位开始,和arr[R]进行比较:

  1. 如果当前位置小于划分值(arr[R]),则交换indexlessR+1的位置,然后index向后移动一位。即 :交换位置index++++lessR
  2. 如果大于划分值,则交换indexmoreL-1的位置, 但是index不移动,但是moreL向前移动一位。即 index--moreL
  3. 如果等于划分值,则index向下移动一位,即:index++

比较直到 indexmoreL相遇为止。
注意:最后还需要将arr[R]moreL交换位置,此时数组完成划分。

 /**
     * 数组arr[L...R]范围上用arr[R]划分,返回等于arr[R]的范围
     * partition  划分;分层
     * @param arr
     * @param L
     * @param R
     */
    public static int[] partition(int[] arr,int L ,int R){
        //lessR:小于划分值arr[R]的做右边位置
        int lessR = L - 1;
        //moreL:大于划分值arr[R]的最左边位置
        int moreL = R;
        //index:当前位置
        int index = L;
        while (index < moreL){
            if (arr[index] < arr[R]){
                //小于arr[R] 交换lessR 和 index 的位置,index向下一位(即index++),lessR自增一位(先自增在使用即++lessR)
                swap(arr,index++,++lessR);
            }else if (arr[index] > arr[R]){
                //大于arr[R] ,交换moreL和index 的位置,index位置不变,moreL向前一位(先减一再使用即--moreL)
                swap(arr,index,--moreL);
            }else {
                //等于arr[R],不交换,index向下一位
                index++;
            }
            //当index指针和moreL重合,跳出循环;所以最后index和moreL的值是一样的。
        }
        swap(arr,index,R);
        return new int[] {lessR+1,moreL};
    }

二、递归方法

 	/**
     * 快速排序1 递归实现
     * @param arr
     */
    public static void quickSort1(int[] arr){
        if (arr == null || arr.length < 2){
            return;
        }
        process(arr,0,arr.length-1);
    }
    /**
     * 快速排序-递归过程
     * @param arr
     * @param L
     * @param R
     */
    public static void process(int[]arr,int L,int R){
        if (L >= R){
            //如果 L>R 无效范围,如果L=R只有一个数,都直接返回
            return;
        }
        //L<R
        //将arr[L...R]范围上划分
        int [] equal = partition(arr,L,R);
        //equal[0] 等于区域的第一个数
        //equal[1] 等于区域的最后一个数
        //将等于区域左边的重新排序
        process(arr,L,equal[0]-1);
        //将等于区域右边的重新排序
        process(arr,equal[1]+1,R);
    }

三、非递归方法

定义一个Job辅助类,存放L和R边界,

 	/**
     * 快速排序-非递归实现
     * @param arr
     */
    public static void quickSort2(int[] arr){
        if (arr == null || arr.length < 2){
            return;
        }
        Stack<Job> stack = new Stack<>();
        Job job = new Job(0, arr.length - 1);
        stack.push(job);
        while (!stack.isEmpty()){
            Job cur = stack.pop();
            //从栈去除任务,进行划分
            int[] queals = partition(arr, cur.L, cur.R);
            if (queals[0] > cur.L){
                //等于区域的最小值 大于L 说明存在小于区域
                stack.push(new Job(cur.L,queals[0]-1));
            }
            if (queals[1] < cur.R){
                //等于区域的最大值 小于R 说明存在大于区域
                stack.push(new Job(queals[1]+1,cur.R));
            }
        }

    }

    public static class Job{
        public int L;
        public int R;

        public Job(int L,int R){
            this.L = L;
            this.R = R;
        }
    }

四、测试

对数器

    /**
     * 通过对数器测试
     * @param args
     */
    public static void main(String[] args) {

        int testTime = 500000;
        int maxSize = 100;
        int maxValue = 100;
        boolean succeed = true;
        System.out.println("=====测试开始=====");
        for (int i = 0; i < testTime; i++) {
        	//随机生成数组
            int[] arr1 = generateRandomArray(maxSize, maxValue);
            //复制数组
            int[] arr2 = copyArray(arr1);
            quickSort1(arr1);
            quickSort2(arr2);
            //进行对比
            if (!isEqual(arr1, arr2) ) {
                System.out.println("排序错误!");
                succeed = false;
                break;
            }
        }
        System.out.println("=====测试结束=====");
        System.out.println(succeed ? "成功!" : "失败!");
    }

其他方法

//交换位置
 public static void swap(int[]arr, int i ,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    /**
     * 生成随机数组
     * @param maxSize
     * @param maxValue
     * @return
     */
    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;
    }

    /**
     * 复制数组
     * @param arr
     * @return
     */
    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;
    }

    /**
     * 判断数组是否相同
     * @param arr1
     * @param arr2
     * @return
     */
    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;
    }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Liu_Shihao

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值