快速排序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;
}


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

相关文章
|
消息中间件 Java API
RocketMQ事务消息, 图文、源码学习探究~
介绍 RocketMQ是阿里巴巴开源的分布式消息中间件,它是一个高性能、低延迟、可靠的消息队列系统,用于在分布式系统中进行异步通信。 从4.3.0版本开始正式支持分布式事务消息~ RocketMq事务消息支持最终一致性:在普通消息基础上,支持二阶段的提交能力。将二阶段提交和本地事务绑定,实现全局提交结果的一致性。 原理、流程 本质上RocketMq的事务能力是基于二阶段提交来实现的 在消息发送上,将二阶段提交与本地事务绑定 本地事务执行成功,则事务消息成功,可以交由Consumer消费 本地事务执行失败,则事务消息失败,Consumer无法消费 但是,RocketMq只能保证本地事务
|
前端开发 关系型数据库 容器
利用Canvas进行绘制XY坐标系
原文:利用Canvas进行绘制XY坐标系 首先来一发图 绘制XY的坐标主要是利用Canvas setLeft和setBottom功能(Canvas内置坐标的功能) 1.首先WPF中的坐标系都是从左到右,从上到下的 即左上角位置(0,0)点,所以XY的Canvas要以(RenderTransf...
1872 0
|
8月前
|
Java 数据库连接 数据库
【潜意识Java】使用 Ruoyi 框架开发企业级应用,从零开始的实践指南和分析问题
本文介绍了基于Spring Boot的开源企业级框架Ruoyi,涵盖环境搭建、项目初始化及用户管理模块的创建。
827 4
|
10月前
|
JSON 前端开发 JavaScript
如何根据响应状态码进行错误处理?
【10月更文挑战第29天】通过对不同响应状态码进行有针对性的错误处理,可以提高应用程序的健壮性和用户体验。在实际开发中,还可以根据具体的业务需求和应用场景,对错误处理进行更细致的优化和扩展,确保应用程序在各种情况下都能友好地与用户进行交互。
|
7月前
|
机器学习/深度学习 人工智能
Diffusion-DPO:一种基于直接偏好优化的扩散模型对齐新方法
本文介绍了一种名为 Diffusion-DPO 的创新方法,该方法基于直接偏好优化(DPO)原理,简化了扩散模型与人类偏好的对齐过程。相比传统的基于人类反馈的强化学习(RLHF)方法,Diffusion-DPO 避免了显式奖励模型的训练,通过数学近似简化实现流程,并在处理开放词汇表场景时展现出更强的能力。实验结果表明,该方法在 Stable Diffusion 1.5 和 SDXL-1.0 等主流模型上显著提升了生成图像的质量和可控性,为未来扩散模型的发展提供了新的思路。
521 14
Diffusion-DPO:一种基于直接偏好优化的扩散模型对齐新方法
|
机器学习/深度学习 数据采集 算法
Python实现GBDT(梯度提升树)回归模型(GradientBoostingRegressor算法)项目实战
Python实现GBDT(梯度提升树)回归模型(GradientBoostingRegressor算法)项目实战
|
人工智能
Suno教程篇:音乐小白也能使用Suno AI零门槛创作音乐?从此只听AI写的歌!
本文是一篇Suno AI音乐创作工具的教程,指导音乐小白如何使用Suno AI零门槛创作音乐,包括准备工作、基础使用、歌曲风格的选择、歌词填入技巧,以及通过实例展示如何为不同场景生成背景音乐。
Suno教程篇:音乐小白也能使用Suno AI零门槛创作音乐?从此只听AI写的歌!
|
消息中间件 监控 前端开发
RabbitMQ插件详解:rabbitmq_web_stomp【RabbitMQ 六】
RabbitMQ插件详解:rabbitmq_web_stomp【RabbitMQ 六】
1130 0
|
机器学习/深度学习 人工智能 并行计算
【人工智能】CPU、GPU与TPU:人工智能领域的核心处理器概述
在人工智能和计算技术的快速发展中,CPU(中央处理器)、GPU(图形处理器)和TPU(张量处理器)作为核心处理器,各自扮演着不可或缺的角色。它们不仅在性能上各有千秋,还在不同的应用场景中发挥着重要作用
757 2