排序--------快速排序及其优化(Java)

本文深入探讨了快速排序算法的基本原理及其优化策略,包括解决数组接近有序、大量重复元素导致的性能问题,以及三路快排的实现方式。通过随机选取基准值、二路快排和三路快排等优化手段,提高了算法的效率和稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

算法思路:

从待排元素中选取任意一个元素,把它当做分区点(基准值),在遍历的时候比基准值小的放在他的左边,比基准值大的放在右边。在一次遍历结束后,基准元素在最终位置

 

稳定行:不稳定算法,

扩展问题:如何在O(n)的适建范围内找到一个无需数组的k大元素

方法一:递归方法

 

优化

1..当排序的集合几乎接近有序时,由于默认选择的第一个元素作为基准值,会导致基准值划分的两个子树组严重不均衡,此时分层下来的结果近乎n层,此时快拍退化为复杂度为O(n^2)的排序算法

问题:可能一边数组特别多某一边数组特别少,两边的长度不均衡。

解决思路:随机选取一个元素作为基准值,来降低每次都选到最小或最大数的概率。

       public static void quickSortInternal(int[] arr,int left,int right){
            if(left>=right)//结束条件
                return;
            int q=partion1(arr,left,right);//基准值
            quickSortInternal(arr,left,q-1);//递归左边的数组
            quickSortInternal(arr,q+1,right);//递归右边的数组

    }
    //随机选取一个元素作为基准值,来降低每次都选到最小或最大值的概率
    public static int partion1(int[] arr,int left,int right){
        //返回下标l...r的任意一个数
        /**
         * Math.random():产生0~1之间的任意一个小数
         * right-left+1:数组长度
         * +left:保证从left开始
         */
        int randomIndex=(int)((Math.random())*(right-left+1)+left);
        swap(arr,left,randomIndex);//交换当前元素和基准值
        int v=arr[left];//基准值
        //arr[left+1...j]<V
        int j=left;
        //arr[j+1...i-1]>V
        int i=left+1;
        for(;i<=right;i++){
            if(arr[i]<v){
                swap(arr,j+1,i);
                j++;
            }
        }
        //交换left和j元素
        swap(arr,left,j);
        return j;

    }

    private static void swap(int[] arr, int A, int B) {
        int tmp=arr[A];
        arr[A]=arr[B];
        arr[B]=tmp;

    }

 

2.当排序集合包含大量重复的元素,由于基准值相等的元素个数太多,导致数组长度不均衡,此时分层下来的结果近乎n层,亏安排退化为O(n^2)

问题:如果把相同的元素放在一边,会导致一边的数组变长,一边变短。

解决思路:二路快排:(保证了基准值的左右两边都比较均衡,不会因为基准值导致两边不均衡)  分了小于大于区域

  • 将大于或者小于基准值得元素放在数组的两边
  • 索引i不断向后扫描,当i的元素小于基准值时,i++;
  • j索引不断向前扫描,当j的元素大于基准值时,j--,
  • 当i碰到一个>=基准值的元素及j碰到一个小于基准值的元素时,交换i和j的元素,然后i++,j--
   public static void quickSortInternal(int[] arr,int left,int right){
            if(left>=right)//结束条件
                return;
            int q=partion2(arr,left,right);//基准值
            quickSortInternal(arr,left,q-1);//递归左边的数组
            quickSortInternal(arr,q+1,right);//递归右边的数组

        }
private static void swap(int[] arr, int A, int B) {
        int tmp=arr[A];
        arr[A]=arr[B];
        arr[B]=tmp;

    }
    //优化二:解决大量重复元素导致基准值两边的数组长度不均衡问题
    public static int partion2(int[] arr,int left,int right){
        //产生一个在数组范围内的随机数,做基准值
        int randomIndex=(int)(Math.random()*(right-left+1))+left;
        //把左边元素和产生的随机数交换
        swap(arr,left,randomIndex);
        //基准值
        int v=arr[left];
        //arr[left+1...i-1]
        int i=left+1;//左边索引
        //arr[j+1...right]
        int j=right;//右边索引
        while(true){
            //从前向后扫描找比基准值大的数
            while(i<=right&&arr[i]<v)   i++;
            //从前向后扫描找比基准值小
            //
            // 的数
            while(j>=left+1&&arr[j]>v)  j--;
            if(i>j){
                break;
            }
            swap(arr,i,j);
            i++;
            j--;
        }
        swap(arr,left,j);
        return j;
    }

 

3.三路快排:针对于有大量重复元素的数组进行排序

对里面的大于小于,和等于都做了区分。它之排序里面值比较大于或者小于基准值的元素,

 public static void partion3(int[] arr,int left,int right){
        int n=arr.length;
        if(n<=1)
            return ;
        quickSortInternal2(arr,0,n-1);
    }

    private static void quickSortInternal2(int[] arr, int left, int right) {
        if(left>=right)//终止条件
            return;
        //产生一个随机的基准值,减少取最小的值做基准值的机会
        int randomIndex=(int)((Math.random()*(right-left+1))+left);
        //把当前的值和基准值交换
        swap(arr,left,randomIndex);
        //定义基准值
        int v=arr[left];

        //arr[left+1...leftT]<v   小于V的数
        int lt=left;
        //arr[gt....r]>v  大于V的数
        int gt=right+1;
        //从下一个位置开始扫描
        int i=left+1;
        while(i<gt){
            if(arr[i]<v){
                swap(arr,lt+1,i);
                lt++;
                i++;
            }else if(arr[i]>v){
                swap(arr,gt-1,i);
                gt--;
            }else {
                i++;
            }
        }
        swap(arr,left,lt);
        //这里只用递归大于和小于基准值的数,等于的不用管
        quickSortInternal2(arr,left,lt-1);
        quickSortInternal2(arr,gt,right);
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值