随机快排专题 两种方式的随机快排(使用Java实现)

什么是随机快排

随机快速排序(QuickSort)是一种高效的排序算法,其基本思想是选择一个基准元素(pivot),将数组分为两部分:小于基准元素和大于基准元素的部分,然后递归地对这两部分进行排序,最终得到有序数组。
在这里插入图片描述

随机快速排序的主要步骤如下:

1.选择一个基准元素(pivot),通常选择第一个或第二个元素作为基准。
2.将数组分为两部分:小于基准元素和大于基准元素的部分。
3.递归地对这两部分进行排序。
4.合并两个有序的子数组。

注意事项

随机快速排序的时间复杂度为O(nlogn),比标准的快速排序(O(nlogn))快得多。但是,它的随机性和不可预测性导致其在某些情况下可能比标准的快速排序更差。因此,在实际应用中,需要根据具体情况选择适合的排序算法。

随机快排第一版

随机选出一个数字,将大于他的放右边,小于它的放左边,最后返回这个值的下标,根据这个下标,将数组分成两个部分,然后在两个数组内重复进行上面操作,这里采用递归不断重复上面操作即可。

实现将数组分层的代码(大于放右边小于放左边,实现分层)

 /**
     *
     * @param arr
     * @param L 数组左边界
     * @param R 数组右边界
     * @return
     */
    public static int partition(int[]arr,int L,int R){
        if (L > R){
            return -1;
        }
        if (L == R){
            return L;
        }
        //左边分层,最开始没有左边数据时,我们先记成L-1
        int less = L - 1;
        //移动的指针,通过index 不断移动进行比较
        int index = L;
        //R 位置上的数字是我们选中来作为基准的数字,因此比较时,不能超过R 。
        while (index < R){
            //当小于基准数字时,小于区域向右移动,less 要先自增在交换,
            if (arr[index] < arr[R]){
                Utils.swapTemp(arr,index,++less);
            }
            //然后指针下移一位,继续比较。
            index++;
        }
        //最后将R 位置的数字和less的下一个位置的数字进行交换,这时就实现了分层,
        Utils.swapTemp(arr,++less,R);
        //返回基准数字的下标。
        return less;
    }

递归调用

先对数组进行分层,分层后形成两个数组,然后分别对大于区域的数组和小于区域的数组不断进行递归分层,最终实现有序。

 /**
     * 递归方法
     * @param arr
     * @param L
     * @param R
     */
    public static void process(int[]arr,int L,int R){
    	//base case 
        if (L >= R){
            return;
        }
        //这一步是实现随机的。因为我们用R 位置上的数字作为基准数字,为了实现是随机的,我们对这个位置上的数字进行随机交换。
        Utils.swapTemp(arr,R,L+(int)(Math.random()*(R - L + 1)));
        //先进行分层,分层后的子数组不断进行递归
        int partition = partition(arr, L, R);
        //对小于区域进行递归
        process(arr,L,partition - 1);
        //大于区域的数组进行递归
        process(arr,partition+1,R);
    }

最后来个主方法调用,大功告成。

 public static void quickSort(int[]arr){
        if (null == arr || arr.length < 2){
            return;
        }
        process(arr,0,arr.length-1);
    }

这里用到了一个交换的方法,比较简单,也贴出来吧。

	/**
	Utils.swapTemp(arr,R,L+(int)(Math.random()*(R - L + 1)));
	*/
  public static void swapTemp(int[]arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

增强版的随机快排(推荐掌握这种加强版的就可以,效率更好一点)

加强版的区别是什么呢,就是还是选出一个基准数字,现在把大于的放右边,小于的放左边,等于的放中间,现在就形成了三块区域,大于小于和等于,我们把等于的区域左边界和右边界下标返回出去,根据这两个小标,去判定小于区域的数组区间和大于区域的数组区间,再对两个数组进行递归调用

加强版的分层方式,直接上代码

 /**
     * 随机快排
     * @param arr
     * @param L 左边界
     * @param R 右边界
     * @return
     */
    public static int[] partition2(int[]arr,int L,int R){
    	//防止报错
        if(L > R){
            return new int[]{-1,-1};
        }
        //只有一个数字时 直接返回
        if (L == R){
            return new int[]{L,R};
        }
        //左边区域最开始没有元素呢,下标先记为L - 1
        int less = L - 1;
        //大于区域,我们是以R 位置为基准数字去比较,因此大于区域不包含R 
        //所以大于区域的下标记为R 位置
        int more = R;
        //记性比较的下标
        int index = L;
       while(index < more){
       		//等于时下标向右移动不发生交换
            if (arr[index] == arr[R]){
                index++;
            }else if(arr[index] < arr[R]) {
            //小于时,当前数字和less 的下一位进行交换,下标向右移动
                Utils.swapTemp(arr,++less,index++);
            }  else{
            		//当大于基准数字时,我们和右边more的左边一位进行交换,more也要移动到左边位置。index 保持不动,以为交换来的数字还没进行比较,
                Utils.swapTemp(arr,--more,index);
            }
        }
        //最后将R 位置的数字和more 进行交换,交换后,等于区域的右边界就成more位置了,左边界为less+1;
        Utils.swapTemp(arr,R,more);
        return new int[]{less+1,more};
    }

开始递归调用

  public static void process2(int[]arr,int L ,int R){
        if (L >= R){
            return ;
        }
        Utils.swapTemp(arr,R,L+(int)(Math.random()*(R - L + 1)));
        int[] equal = partition2(arr, L, R);
        //对小于区域继续分层
        process2(arr,L,equal[0]-1);
        // 对大于区域进行分层
        process2(arr,equal[1]+1,R);
    }

最后主方法调用。完结撒花

  public static void quickSort2(int[]arr){
        if (arr == null || arr.length < 2){
            return;
        }
        process2(arr,0,arr.length-1);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值