三路快速排序

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

双路快速排序的核心思想:单路快排会将等于V的元素分配在左侧或者右侧,当数组中有大量重复元素时,这将会导致左右两侧的元素数量极度不均衡,时间复杂度退化到O(n^2),,如下图所示:为了避免该问题,双路快排是将等于V的部分近乎平均的分配在左右两侧;三路快排是将等于V的部分集中到中间,左右两侧分别为小于V和大于V的部分,这样不用对大量等于V的元素重复操作,可以一次性把大量重复元素排好序

说明:三路快排只对有大量重复数据的排序效率比较高,普通数据或者基本有序的数据效率虽然不如双路快排和基础快排,总体来说三路快排的性能是比较有保证的,一般情况下系统排序都会选择三路快排,运行效率如下图:

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

  1. lt指向L的位置,i指向L+1的位置,gt指向r+1的位置
  2. 如果i指向的元素等于V,则i++考察下一个元素
  3. 如果i指向的元素小于V,则交换lt+1与i指向的元素,,然后lt++,并且i++考察下一个元素
  4. 如果i指向的元素大于V,则交换gt-1与i指向的元素,然后gt--,注意此时i无需自增,因为i指向的是未被处理的元素
  5. 循环上述步骤,直到i==gt,循环结束
  6. 交换L与lt指向的元素,注意交换后lt指向的元素等于V
  7. 逐层递归,直到所有的元素有序,注意下次迭代秩序排序[l, lt-1]和[gt, r]两部分,等于V的部分无需再次排序

代码如下:

template<typename T>
void quickSort3Ways(T arr[],int n) {
    _quickSort3Ways(arr, 0, n - 1);
}

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

    // 随机在arr[rangeR, rangeL]的范围中, 选择一个数值作为标定点pivot
    swap(arr[rangeL], arr[rand() % (rangeR - rangeL + 1) + rangeL]);

    T temp = arr[rangeL];

    int lt = rangeL;     // arr[rangeL+1,lt] < temp
    int gt = rangeR + 1; // arr[gt...rangeR] > temp
    int i = rangeL + 1;    // arr[lt+1...i) == temp
    while (i < gt) {
        if (arr[i] < temp) {
            swap(arr[i], arr[lt + 1]);
            i++;
            lt++;
        }
        else if (arr[i] > temp) {
            swap(arr[i], arr[gt - 1]);
            gt--;
        }
        else { // arr[i] == temp
            i++;
        }
    }

    //交换之后arr[lt] = temp 
    swap(arr[rangeL], arr[lt]); 

    _quickSort3Ways(arr, rangeL, lt - 1);
    _quickSort3Ways(arr, gt, rangeR);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值