【算法】双轴快排

双轴快排
  • 双轴快排是单轴快排的改进,初次学习双轴快排需要仔细深入地理解各处细节,因此本小节将详细介绍其实现细节,展示确定双轴位置既区间划分的过程。

  • 前述快排每次递归确定当前区间的主轴,并利用该主轴将当前区间划分为左右两个部分。双轴快排则以 两个轴 (pivot1, pivot2)将当前区间划分为 三个子区间,双轴三区间的划分结果要满足如下。为方便叙述,将[left, pivot1)称作区间1,(pivot1, pivot2)称作区间2,(pivot2, right]称作区间3,其中pivot1,pivot2指的是最终位置,区间1,区间2,区间3均指划分后的最终区间。

arr[i] < arr[pivot1], i ∈ [left, pivot1) 区间1
arr[pivot1] ≤ arr[i] ≤ arr[pivot2], i ∈ (pivot1, pivot2) 区间2
arr[i] > arr[pivot2], i ∈ (pivot2, right] 区间3
对三个子区间执行同样的过程,直到无法划分时排序完成。算法主要过程和说明如下,结合后续代码实现的注释可准确把握各处细节。

dualPivotQuickSort执行开始,首先以if(left < right)为条件,只对大小大于等于2的区间执行双轴快排。

以如下语句令左右两端元素中较小者居左,后续以left为初始pivot1(下标),right为初始pivot2(下标),保证pivot1为左右两端元素中的较小者。

在程序后续内容中,arr[left]为pivot1的值(左轴值),arr[right]为pivot2的值(右轴值)。

if(arr[left] > arr[right]) {
swap(arr, left, right);
}
设置index = left + 1,lower = left + 1,upper = right - 1。

index表示当前考察的元素下标。

lower是用于推进到pivot1最终位置的动态向右扩展的下标(扩展区间1),在程序的任意时刻总有[left, lower)的元素确定在区间1中。

upper是用于推进到pivot2最终位置的动态向左扩展的下标(扩展区间3),在程序的任意时刻总有(upper, right]的元素确定在区间3中。

  • 当循环结束时lower–和upper++为最终的pivot1和pivot2的位置。

  • 初始时lower == left + 1,表示区间1元素个数为1,
    因为lower以左(不含lower)才是确定在区间1中的元素。
    在遍历结束后以两个swap完成双轴归位时,
    最后一个确定在区间1的元素会与arr[left]交换。
    所以说我们一开始就知道left处的元素最终一定在区间1中,
    因此初始时令lower == left + 1。

  • upper == right - 1的初始取值也是基于同样的原因。

  • 如果现在还无法很好地理解这一点,先将整个过程看完后再回过头来多推敲几次。

从此处开始,代码行为是要遍历从left + 1到right - 1的所有元素,通过与arr[left] (左轴值)和arr[right] (右轴值)的比较,以及元素交换操作,将 每一个元素正确地置于区间1,区间2和区间3中,与此同时,以lower的动态右移和upper的动态左移,不断扩展这三个区间。 通过index++,从左到右依次遍历所有元素,当所有元素遍历完成,也就意味着所有元素都已归于其应属的区间。显然,这些操作应在一个 循环 之内,下面进入该循环。

首先,循环的边界条件是while(index <= upper)。虽然还未开始分析upper的动态变化,但已经知道upper以右(不含upper)的元素是确定在区间3中的,index向右推进的时候不能超过upper,因为下标为upper + 1的元素是已确定在区间3中的 (但下标为upper的元素尚未确定其归属),所以是 <=。

以if(arr[index] < arr[left])考察arr[index]是否应在区间1,若满足则在区间1。这意味需要将该元素置于lower左侧,且区间1需向右扩展1位,通过如下两行,交换arr[index]和arr[lower]后lower++来完成。

swap(arr, index, lower); 
lower++;

类似地,以else if(arr[index] > arr[right])考察arr[index]是否应在区间3,若满足则在区间3。这意味着需要将

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值