leetcodeT912-快排优化-三路划分

简介: leetcodeT912-快排优化-三路划分

1.前言

因为快排的名声太大

并且快排在某些场景下比较慢,所以leetcode"修理"了一下快排

特意设计了一些专门针对快排的测试用例

所以用快排过不了这一题

2.为什么需要三路划分的优化?

我们遇到了第一个为难快排的测试用例全是重复值2

我们发现快排在遇到全是重复值的数据时,

这里以左右指针法为例

每次右指针从右向左找小时都要跑到左指针位置处

然后进行交换,递归

每次都只能把那个重复数据2放到当前递归区间的起始位置,就像是冒泡排序一样每次只能冒一个数到对应位置,但是冒泡排序好歹还能有一个优化(没有发生数据交换时即为有序,排序结束),可是这时快排连优化都没有

退化到了O(n^2)的时间复杂度

3.三路划分的思想及举例画图

这是整个过程,大家也可以自己对照三种情况画一下

一趟三路划分

前:

后:

我们发现:

一趟三路划分后整个数组被分为三个部分:

假设区间左端点:begin,右端点:end

[begin,l-1]:这一段上区间的值小于key

[l,r] :这一段上区间的值等于key

[r+1,end]:这一段上区间的值大于key

等于key的那一段区间不需要递归了,因为它们已经位于它们该在的地方了

接下来只需要递归[begin,l-1],[r+1,end]即可

4.三路划分的代码实现

//三路划分
void QuickSort(int* a, int begin, int end)
{
  if(begin>=end)
    {
        return;
    }
    int keyIndex=GetMidIndex(a,begin,end);
    Swap(&a[begin],&a[keyIndex]);
    int key=a[begin];
    int left=begin,right=end,cur=begin+1;
    while(cur<=right)
    {
        if(a[cur]<key)
        {
            Swap(&a[cur],&a[left]);
            cur++;
            left++;
        }
        else if(a[cur]==key)
        {
            cur++;
        }
        else
        {
            Swap(&a[cur],&a[right]);
            right--;
        }
    }
    QuickSort(a,begin,left-1);
    QuickSort(a,right+1,end);
}

所以我们可以发现,三路划分之后,数组中重复越多,我们快排就越快

因为重复值直接就跳过了

对于那个测试用例来说

第一趟排序之后left还是等于begin,right还是等于end

所以再往下递归就会触发begin>=end这个条件,就会直接返回

所以达到了O(n)的时间复杂度

所以对于这个测试用例来说已经比较快了

5.三数取中修改

但是:

尽管我们通过了所有的测试用例,但是因为耗时太长leetcode直接针对快排

那么怎么办,怎么过呢?

我们去掉三数取中优化,看一下是哪个测试用例对我们的针对

这里我们打印了一下数组开头,中间,结尾的那三个数

这个题目最大值是50000,

这个测试用例最大值是上万,而我们三数取中取出来的是7500,相对来说偏小了

所以我们要对三数取中的mid搞一个随机数

只需要在三数取中的代码中给mid一个随机值即可

这里设置随机数种子,避免出现rand函数产生的重复值不变的情况

尽管我们过是过了,但是Leetcode这一题的测试用例太针对快排了

所以快排被欺负的很惨

以上就是leetcodeT912针对快排的三路划分优化的讲解,希望能对大家有所帮助!

相关文章
|
算法
快排三种递归及其优化,非递归和三路划分
快排三种递归及其优化,非递归和三路划分
63 0
|
人工智能 算法
【算法分析与设计】递归与分治策略(二)
【算法分析与设计】递归与分治策略
|
算法
建筑抢修 (大根堆+贪心+优先队列+快速排序+2重思想比较)
建筑抢修 (大根堆+贪心+优先队列+快速排序+2重思想比较)
46 0
|
机器学习/深度学习 算法 编译器
【算法分析与设计】递归与分治策略(一)
【算法分析与设计】递归与分治策略
|
搜索推荐
图解:快速排序算法之双边循环法
之前我们学习了冒泡排序,有没有比冒泡排序更快的排序算法呢?当然有,例如快速排序,归并排序,堆排序。接下来即将介绍的快速排序就是由冒泡排序演变而来的。
191 0
图解:快速排序算法之双边循环法
|
搜索推荐
“掌握更多的快速排序技巧:三路划分、双路快排和非递归的深入理解”(上)
“掌握更多的快速排序技巧:三路划分、双路快排和非递归的深入理解”(上)
176 0
|
6月前
|
算法 搜索推荐
归并算法:分治而治的高效算法大揭秘(图文详解)
归并算法:分治而治的高效算法大揭秘(图文详解)
100 0
|
算法 搜索推荐 Windows
【算法分析与设计】递归与分治策略(三)
【算法分析与设计】递归与分治策略
|
算法
图解:快速排序之单边循环法
单边循环法是快速排序的算法之一,之前的双边循环法从数列的两边交替遍历元素,虽然更加直观,不过代码实现起来相对复杂。而单边循环法就要简单多了,只需要从数组的一边对元素进行遍历和交换即可。
201 0
图解:快速排序之单边循环法