zoukankan      html  css  js  c++  java
  • 三路快速排序算法

    1、三路快速排序算法的基本思想

    之前的快速排序算法都是将序列分成<=v和>v或者是<v和>=v的两个部分,而三路快速排序是

    将序列分成三个部分:<v、=v、>v,如下图所示:

    首先v元素还是作为"基准"元素,e表示当前遍历索引值指向的元素,也就是待考虑的元素,从图中可以

    看出来,整个序列被分成3个部分,也就是说当我们遍历完成之后整个序列就已经被分成了<v、=v、>v

    三个部分了,而我们只需要对<v和>v的两个部分再次递归调用三路排序函数进行排序即可,来看看具体

    的过程:

    首先来看看整个序列的布局,这里我们使用了3个索引值来表示3个不同的位置,使用lt索引来表示

    <v部分和=v部分的分界处(这里选的是<v部分的最后一个元素),使用i索引表示遍历的位置,

    使用gt索引来表示=v部分和>v部分的分界处(这里选的是>v部分的第一个元素)。

     如果当前i指向的元素=v,那直接就将此元素归为=v部分,i++即可

     如果当前i指向的元素<v,将此元素与=v部分的第一个元素

                                                                   交换位置,也就是swap(arr[i], arr[lt+1]),之后将lt++,

                                                                   i++即可,此时<v部分就多了一个元素

     如果当前i指向的元素>v,则将此元素与>v部分的第一个元

                                                                  素的前一个元素交换位置,也就是swap(arr[i], arr[gt-1]),

                                                                  然后gt--,表示>v部分多了一个元素此时i不用动,因为他指

                                                                  向的元素是交换过来的,这个元素还没有遍历到。

     当gt与i重合的时候就表示便利完毕了,那么此时我们只需要

                                                                   将l指向的元素v与lt交换位置即可,之后就如下所示了

     

    之后我们只需要对<v和>v这两部分再次递归进行三路排序,而对于=v的部分就不用在考虑了,因为他们

    已经放在了合适的位置了,所以从这里可以看出来如果=v部分元素非常多,那么我们的三路快速排序算法

    效果就会越明显,这也正是他的优点所在。

    2、三路快速排序算法的实现(基于C++)

    首先说明,代码中使用到的索引值变量都是取之于上面的图示中,这样便于描述问题

     1 /**************************************三路快速排序算法实现***********************************/
     2 template<typename T>
     3 void __quickSort3Ways (T arr[], int left, int right)
     4 {
     5     if (right - left <= 40) {                  /* 对递归到数据量较小时使用插入排序 */
     6         __insertSortMG<T>(arr, left, right);
     7         return;
     8     }
     9 
    10     std::swap(arr[left], arr[std::rand() % (right - left + 1) + left]);  // 随机化找到一个元素作为"基准"元素 
    11     T v = arr[left];
    12 
    13     int lt = left;       // 将<v的分界线的索引值lt初始化为第一个元素的位置(也就是<v部分的最后一个元素所在位置)
    14     int gt = right + 1;  // 将>v的分界线的索引值gt初始化为最后一个元素right的后一个元素所在位置(也就是>v部分的第一个元素所在位置)     
    15     int i = left + 1;    // 将遍历序列的索引值i初始化为 left+1
    16     
    17     while (i < gt) {     // 循环继续的条件
    18         if (arr[i] < v) {
    19             std::swap(arr[i], arr[lt + 1]);  // 如果当前位置元素<v,则将当前位置元素与=v部分的第一个元素交换位置 
    20             i++;                             // i++  考虑下一个元素
    21             lt++;                            // lt++  表示<v部分多了一个元素
    22         }
    23         else if (arr[i] > v) {               // 如果当前位置元素>v,则将当前位置元素与>v部分的第一个元素的前一个元素交换位置
    24             std::swap(arr[i], arr[gt - 1]);  // 此时i不用动,因为交换过来的元素还没有考虑他的大小
    25             gt--;                            // gt--  表示>v部分多了一个元素
    26         }
    27         else {              //  如果当前位置元素=v   则只需要将i++即可,表示=v部分多了一个元素
    28             i++;
    29         }
    30     }
    31 
    32     std::swap(arr[left], arr[lt]);   // 上面的遍历完成之后,将整个序列的第一个元素(也就是"基准"元素)放置到合适的位置 
    33                                      // 也就是将它放置在=v部分即可
    34     __quickSort3Ways<T>(arr, left, lt - 1); // 对<v部分递归调用__quickSort3Ways函数进行三路排序
    35     __quickSort3Ways<T>(arr, gt, right);    // 对>v部分递归调用__quickSort3Ways函数进行三路排序
    36 }
    37 
    38 template<typename T>
    39 void quickSort3Ways (T arr[], int count)
    40 {
    41     std::srand(std::time(NULL));               /* 种下随机种子 */
    42     __quickSort3Ways<T>(arr, 0, count - 1);    /* 调用__quickSort3Ways函数进行三路快速排序 */
    43 }
    44 /***********************************************************************************************/

    3、性能测试

    一般排序序列:

    大量重复元素序列:

    近乎有序状态的序列:

  • 相关阅读:
    【Azure Redis 缓存】Azure Redis 功能性讨论二
    【Azure Developer】如何用Microsoft Graph API管理AAD Application里面的Permissions
    【Azure 环境】通过Python SDK收集所有订阅简略信息,例如订阅id 名称, 资源组及组内资源信息等,如何给Python应用赋予相应的权限才能获取到信息呢?
    【Azure 应用服务】App Service与APIM同时集成到同一个虚拟网络后,如何通过内网访问内部VNET的APIM呢?
    【Azure 云服务】如何从Azure Cloud Service中获取项目的部署文件
    【Azure Redis 缓存】Azure Redis 异常
    【Azure 微服务】基于已经存在的虚拟网络(VNET)及子网创建新的Service Fabric并且为所有节点配置自定义DNS服务
    【Azure Redis 缓存】遇见Azure Redis不能创建成功的问题:至少一个资源部署操作失败,因为 Microsoft.Cache 资源提供程序未注册。
    【Azure Redis 缓存】如何得知Azure Redis服务有更新行为?
    【Azure API 管理】在 Azure API 管理中使用 OAuth 2.0 授权和 Azure AD 保护 Web API 后端,在请求中携带Token访问后报401的错误
  • 原文地址:https://www.cnblogs.com/deng-tao/p/6536302.html
Copyright © 2011-2022 走看看