双路快速排序

双路快速排序的时间复杂度为O(nlog2n),空间复杂度为O(n)

双路快速排序的核心思想:单路快排会将等于V的元素分配在左侧或者右侧,当数组中有大量重复元素时,这将会导致左右两侧的元素数量极度不均衡,时间复杂度退化到O(n^2),如下图所示:
双路快排是将等于V的部分近乎平均的分配在左右两侧,避免了该问题

说明:双路快速排序在等于V的时候也要交换位置,是为了避免大量等于V的元素集中在左侧或者右侧

排序的步骤和示意图如下:

  1. i从l+1的位置开始递增,直到第一个大于等于V的元素
  2. j从r的位置开始递减,直到第一个小于等于V的元素
  3. 两块蓝绿色区域分别归到左侧和右侧,交换i和j指向的元素,并且i ++,j--,可以看出等于V的元素近乎均分在了左右两侧
  4. 继续次操作,直到i >j,注意此时j指向的是最后一个小于等于V的元素,i指向的是第一个大于等于V的元素,所以交换j与L位置的元素,本层双路快排结束
  5. 重复上述步骤,直到所有元素有序

代码如下:

template<typename T>
void quickSort2Ways(T arr[], int n) {
    srand(time(nullptr));
    _quickSort2Ways(arr, 0, n - 1);
}

// 对arr[rangeL,rangeR]部分进行快速排序
template<typename T>
void _quickSort2Ways(T arr[], int rangeL, int rangeR) {
    if (rangeL >= rangeR) {
        return;
    }

    if (rangeR - rangeL <= 16) {
        insertionSort(arr, rangeL, rangeR);
        return;
    }

    int index = _quickPartition2Ways(arr, rangeL, rangeR);

    _quickSort2Ways(arr, rangeL, index - 1);
    _quickSort2Ways(arr, index + 1, rangeR);
}

// 双路快速排序的partition
// 返回p, 使得arr[rangeL,index] <= arr[index] ; arr[index+1,rangeR] >= arr[index]
// 双路快排处理的元素正好等于arr[index]的时候要注意,详见下面的注释:)
template<typename T>
int _quickPartition2Ways(T arr[], int rangeL, int rangeR) {
    // 随机在arr[rangeR, rangeL]的范围中, 选择一个数值作为标定点pivot
    swap(arr[rangeL], arr[rand() % (rangeR - rangeL + 1) + rangeL]);

    T temp = arr[rangeL];

    // arr[rangeL+1,i) <= temp; arr(j,rangeR] >= temp
    int i = rangeL + 1, j = rangeR;
    while (true) {
        // 注意这里的边界, arr[i] < temp, 不能是arr[i] <= temp
        while (i <= rangeR && arr[i] < temp)
            i++;

        // 注意这里的边界, arr[j] > temp, 不能是arr[j] >= temp
        while (j >= rangeL + 1 && arr[j] > temp)
            j--;

        if (i > j)
            break;

        swap(arr[i], arr[j]);
        i++;
        j--;
    }


    swap(arr[j], arr[rangeL]);
    return j;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值