快排优化之 二路快排、三路快排(重点)

二路快排:

不管当条件是大于等于还是小于等于v,当数组中重复元素非常多的时候,那么就将数组分成了极度不平衡的两个部分,因为等于v的部分总是集中在数组的某一边。此时快排的时间复杂度再次退化为O(n^2)级别。

其中一种优化的方式便是进行双路快排。

和单路快排不同的是此时将小于v和大于v的元素放在数组的两端,那么将引用新的索引j的记录大于v的边界位置。
如图:
在这里插入图片描述

i索引不断向后扫描,当i的元素小于v的时候继续向后扫描,直到碰到了某个元素大于等于v。j同理,直到碰到某个元素小于等于v。
如图:
在这里插入图片描述

然后绿色的部分便归并到了一起,而此时只要交换i和j的位置的元素就可了,然后i++,j–就行了。
如图:
在这里插入图片描述

eg:二路快排分区函数实现

    private static int partition2(int[] array,int l,int r) {
// 随机选取待排序数组中的任意一个元素
        int randomIndex = (int) (Math.random()*(r-l+1) + l);
        swap(array,l,randomIndex);
        int v = array[l];
        int i = l+1,j = r;
        while (true) {
            while (i <= r && array[i] < v) i++;
            while (j >= l+1 && array[j] > v) j--;
            if (i > j) {
                break;
            }
            swap(array,i,j);
            i++;
            j--;
        }
// 循环走完后,j索引下标为分区点位置
        swap(array,l,j);
        return j;
}

三路快排:

双路快排将整个数组分成了小于v,大于v的两部分,而三路快排则是将数组分成了小于v,等于v,大于v的三个部分,当递归处理的时候,遇到等于v的元素直接不用管,只需要处理小于v,大于v的元素就好了。某一时刻的中间过程如下图:

在这里插入图片描述

当元素e等于v的时候直接纳入绿色区域之内,然后i++处理下一个元素。
如图:
在这里插入图片描述

当元素e小于v的时候,只需要将元素e与等于e的第⼀一个元素交换就行了,和刚开始讲的快速排序方法类似。
同理,当大于v的时候执行相似的操作。
如图:

在这里插入图片描述

在这里插入图片描述

当全部元素处理完之后,数组便成了这个样子:
在这里插入图片描述

eg:三路快排实现

private static void quickSortInternal3(int[] arr,int l,int r) {
    if (l >= r) {
        return;
    }
    // 随机选取待排序数组中的任意⼀一个元素
    int randomIndex = (int) (Math.random() * (r - l + 1) + l);
    swap(arr, l, randomIndex);
    int v = arr[l];
    // arr[l+1...lt] < v
    int lt = l;
    // arr[lt+1...i-1] == v
    int i = l + 1;// arr[gt...r] > v
    int gt = r + 1;
    while (i < gt) {
        if (arr[i] < v) {
            swap(arr, i, lt + 1);
            lt++;
            i++;
        } else if (arr[i] > v) {
            swap(arr, i, gt - 1);
            gt--;
        } else {
            i++;
        }
    }
    // 循环⾛走完只需要将l位置的元素与lt交换即为分区点
    swap(arr, l, lt);
    quickSortInternal3(arr, l, lt - 1);
    quickSortInternal3(arr, gt, r);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值