快速排序4(三路划分快排)

简介: 快速排序4(三路划分快排)

一、为什么要用三路划分快排?


前面我们已经实现了三个版本的快速排序的算法,分别是hoare法,挖坑法和前后指针法。但是前面的三个版本的快速排序在某些极端场景中效率都会变得很低,例如大部分都是同一个数的时候,前面的三种方法都不能很高效地完成排序,时间复杂度退化成了O(N^2),所以我们有必要对之前的排序方法进行一些改进,使它能够适应包含任何数据的数组。于是就有大佬想出了一个更牛的方法,那就是三路划分快排。


二、三路划分快排的思路


三路划分快排的思路:三路划分,顾名思义就是把数组分成三个部分进行排序,选定一个key,把数组分成小于key的,等于key的,还有大于key的。具体操作是:选定a[left]为key,再定义一个下标cur=left+1,一共就left,cur,right三个下标。从cur开始与key比较,如果a[cur]<key,就用a[cur]和a[left]交换,然后++left,++cur;如果a[cur]>key,就用a[cur]和a[right]交换,–right;如果a[cur]==key,那就++cur,这样循环往复,知道cur>right就结束,最后得到的a[begin,left-1]是比key小的数,a[left,right]是等于key的数,a[cur,end]是大于key的数,划分成三路之后,中间这一路就不用再进行排序了,因为中间这一路都是等于key的,所以已经有序了,只需要对左路和右路再进行递归排序即可。


动图演示如下:




显然,一趟排序之后把数组分成了小于key的,等于key的,还有大于key的。等于key的就不用再操作了,接下来就递归分别对小于key的数和大于key的数进行排序即可。


三、参考代码


void Swap(int* a, int* b)
{
  int tmp = *a;
  *a = *b;
  *b = tmp;
}
void PrintArr(int* a, int n)
{
  int i = 0;
  for (i = 0; i < n; i++)
  {
    printf("%d ", a[i]);
  }
  printf("\n");
}
//三数取中
int GetMidNumi(int* a, int left, int right)
{
  int mid = (left + right) / 2;
  if (a[left] > a[mid])
  {
    if (a[mid] > a[right])
    {
      return mid;
    }
    //来到这里证明a[mid]最小,那么a[left]和a[right]
    //谁小谁就是中间的那个数
    else if (a[left] < a[right])
    {
      return left;
    }
    else
    {
      return right;
    }
  }
  else//a[left]<=a[mid]
  {
    if (a[mid] < a[right])
    {
      return mid;
    }
    //来到这里证明a[mid]最大,那么a[left]和a[right]
    //谁小谁就是中间的那个数
    else if (a[left] < a[right])
    {
      return left;
    }
    else
    {
      return right;
    }
  }
}
//三路划分快排
void ThreeWayQuickSort(int* a, int begin, int end)
{
  //需要先定义局部的left和right进行++和--;
  //不能直接对begin和end操作,因为排完一趟
  //之后需要利用begin和end来确定递归排序的
  //边界
  int left = begin;
  int right = end;
  //区间不存在就可以返回了
  if (left >= right)
  {
    return;
  }
  //三数取中
  int mid = GetMidNumi(a, left, right);
  if (mid != left)
  {
    Swap(&a[mid], &a[left]);
  }
  //选key
  int key = a[left];
  int cur = left + 1;
  while (cur <= right)
  {
    //小于就和a[left]交换,保证小的数在key的左边
    if (a[cur] < key)
    {
      Swap(&a[cur], &a[left]);
      left++;
      cur++;
    }
    //大于就和a[right]交换,保证大的数在key的右边
    else if (a[cur] > key)
    {
      Swap(&a[cur], &a[right]);
      //只需要right--,不能cur++,证明看上图
      right--;
    }
    else
    {
      cur++;
    }
  }
  //边界的确定看上图
  ThreeWayQuickSort(a, begin, left - 1);
  ThreeWayQuickSort(a, cur, end);
}
int main()
{
  int a[] = { 6,6,6,6,1,2,7,9,3,6,6,10,8 };
  int sz = sizeof(a) / sizeof(a[0]);
  ThreeWayQuickSort(a, 0, sz - 1);
  PrintArr(a, sz);
  return 0;
}


以上就是三路划分快排的所有内容了,这个快排可以说是不惧怕任意组合的数据的,无论所给的数组的数据有多么的极端,效率都能很高,这才是最牛的快速排序版本,你学会了吗?

相关文章
|
存储 安全 Windows
徒手帮 process explorer 找回丢失的进程列
徒手帮 process explorer 找回丢失的进程列
|
消息中间件 Java API
RocketMQ事务消息, 图文、源码学习探究~
介绍 RocketMQ是阿里巴巴开源的分布式消息中间件,它是一个高性能、低延迟、可靠的消息队列系统,用于在分布式系统中进行异步通信。 从4.3.0版本开始正式支持分布式事务消息~ RocketMq事务消息支持最终一致性:在普通消息基础上,支持二阶段的提交能力。将二阶段提交和本地事务绑定,实现全局提交结果的一致性。 原理、流程 本质上RocketMq的事务能力是基于二阶段提交来实现的 在消息发送上,将二阶段提交与本地事务绑定 本地事务执行成功,则事务消息成功,可以交由Consumer消费 本地事务执行失败,则事务消息失败,Consumer无法消费 但是,RocketMq只能保证本地事务
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
1666 6
|
6月前
|
搜索推荐 安全 数据可视化
智慧随访系统,随访系统源码,多渠道随访、智能提醒、表单模板库与满意度调查
诊后随访管理系统通过信息化手段,实现患者出院后的全流程健康管理。系统基于模块化架构,集成HIS/EMR数据,支持多渠道随访、智能提醒、表单模板库与满意度调查,提供从计划制定、执行记录到统计分析的一体化解决方案,提升医疗连续性与服务质量。
380 0
|
传感器 JavaScript 调度
HarmonyOS Next 并发 taskpool 和 worker
HarmonyOS Next 提供了 TaskPool 和 Worker 两种并发能力,基于 Actor 并发模型实现。TaskPool 是 Worker 的封装,支持参数直接传递、返回数据接收、任务优先级设置及取消功能,适合大多数场景;Worker 则适用于超长任务或需手动管理线程生命周期的场景。两者通过消息通信完成跨线程数据交换,支持普通对象拷贝、ArrayBuffer 拷贝/转移、SharedArrayBuffer 共享及 Sendable 引用传递等方式。实际开发中,TaskPool 更简化任务调度,而 Worker 更灵活,可根据任务类型(耗时、长时、常驻)选择合适方案。
675 12
HarmonyOS Next 并发 taskpool 和 worker
|
Java 数据库连接 数据库
【潜意识Java】使用 Ruoyi 框架开发企业级应用,从零开始的实践指南和分析问题
本文介绍了基于Spring Boot的开源企业级框架Ruoyi,涵盖环境搭建、项目初始化及用户管理模块的创建。
1837 4
|
算法 搜索推荐 Java
【经典算法】LeetCode 215. 数组中的第K个最大元素(Java/C/Python3实现含注释说明,Medium)
【经典算法】LeetCode 215. 数组中的第K个最大元素(Java/C/Python3实现含注释说明,Medium)
819 3
|
存储 人工智能 调度
直播回放 | 高性能智算集群设计思考与实践
本次分享的主题是高性能智算集群设计思考与实践,由阿里云灵骏智算集群产品解决方案负责人丛培岩分享。 1. AGI对基础设施的挑战 2. 高性能智算集群的设计实践 3. 思考与展望
439 1
|
消息中间件 监控 前端开发
RabbitMQ插件详解:rabbitmq_web_stomp【RabbitMQ 六】
RabbitMQ插件详解:rabbitmq_web_stomp【RabbitMQ 六】
2039 0
|
机器学习/深度学习 数据采集 算法
Python实现GBDT(梯度提升树)回归模型(GradientBoostingRegressor算法)项目实战
Python实现GBDT(梯度提升树)回归模型(GradientBoostingRegressor算法)项目实战

热门文章

最新文章