快速排序算法【从双路快排到三路快排】

快排的基本思想是:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。

对于快速排序来说,区间内的数的大小顺序越随机效率越好,这样就能将数据划为为两个区域;
这点和选择排序恰恰相反,选择排序在数组有序时排序效率较高,而对于快排来说,数据有序反而回导致每次可能都只能划分出一个区域,导致效率下降到O(n^2);

所以为了避免极端测试用例,我们在每次进行排序之前,先将区间第一个数和区间里随机选择的一个数进行交换,保证效率。

双路快排:将与pivot相等的数平均分配到左右两个区间中

	Random random=new Random(System.currentTimeMillis());
	public void quickSort(int []nums,int left,int right){
        if(left>=right) return;
        int randomIndex=left+ random.nextInt(right-left+1);
        swap(nums,left,randomIndex);
        int i=left,j=right;
        int pivot=nums[left];
        while(i<j){
            while(i<j&&nums[j]>=pivot){
                j--;
            }
            if(i<j){
                swap(nums,i++,j);
            }
            while(i<j&&nums[i]<=pivot){
                i++;
            }
            if(i<j){
               swap(nums,i,j--);
            }
        }
        nums[i]=pivot;
        quickSort(nums,left,i-1);
        quickSort(nums,i+1,right);
    }

    public void swap(int []nums,int i,int j){
        int tmp=nums[i];
        nums[i]=nums[j];
        nums[j]=tmp;
    }
    

优化:三路快排
将和pivot相等的数挤压到中间,小于pivot的划分到左边,大于pivot的划分到右边;
之后只需要对左区间和右区间再进行快排即可。
三路快排在有大量相同数据时,可以大幅加快排序的速度。

思路:维护三个变量i,j,k; i的左边是左区间,j的右边是右区间,k用来遍历。
我们从pivot的下标+1处开始遍历,划分好区间后,再把pivot和左区间的最后一个元素交换

	Random random=new Random(System.currentTimeMillis());
 	public void quickSort(int []nums,int left,int right){
        if(left>=right) return;
        int randomIndex=left+ random.nextInt(right-left+1);
        swap(nums,left,randomIndex);
        int i=left+1,j=right,k=left+1;
        int pivot=nums[left];
        while(k<=j){
           if(nums[k]<pivot){
               swap(nums,i++,k++);  //i++,k--,因为交换过来的数k之前九遍历过来,所以无需再看
           }
           else if(nums[k]==pivot){
               k++;
           }
           else{
               swap(nums,k,j--);  //此处k不++,因为交换过来的数k还没遍历过,所以还要再看
           }
        }
        swap(nums,left,i-1);
        quickSort(nums,left,i-2);
        quickSort(nums,j+1,right);
    }

    public void swap(int []nums,int i,int j){
        int tmp=nums[i];
        nums[i]=nums[j];
        nums[j]=tmp;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值