快速排序2(挖坑法)

简介: 快速排序2(挖坑法)

一、什么是挖坑法?


挖坑法的思想是:先保存最左边的left位置的key值,然后最左边的left位置就可以看作是一个“坑”,因为它可以被其他数据覆盖(key已经被保存起来,所以不用担心原来的数据被覆盖掉),然后先从右边right位置开始往左找比key小的数,找到后把这个值填到“坑”里面,那么这个位置就会变成一个新的“坑”,再从左边left位置开始往右找比key大的数,找到后又把它填到“坑”里面,再从右向左找比key小的,以此类推,最后它们一定会在坑里相遇,因为left和right肯定有一个为“坑”,最后把刚开始保存的key值填到这个“坑”里就完成了一趟的快速排序。这个坑的位置也就是hoare版本返回的keyi,以这个坑为分界线,递归对左边的子数组和右边的子数组以同样的方式做快速排序,直到子区间只有一个值(left==right)或者子区间不存在(left>right)的时候就不用再递归下去了。最终就能完成对整个数组的排序。


hoare版本的快排:https://blog.csdn.net/weixin_70056514/article/details/129969288?spm=1001.2014.3001.5502


其实这个挖坑法是有人在基于hoare版本的快排的基础上,对其进行的一个排序的实现方式的改版而已,因为有人觉得hoare版本的快速排序在选key的时候要遵循“左边做key,右边先走”的原则,这个地方也是很多人不太容易理解的地方,很多人都想不明白这是为什么,不太好理解,所以就会记不住,可能有一天写的时候就不记得是左边先走还是右边先走了,容易出错。但是这个挖坑法就很好理解了,因为选左边做key,那么刚开始“坑”就在左边,那自然就是先从right往左找比key小的,然后填到左边这个坑里,形成新“坑”,再从left往右找比key大的填到坑里,以此类推,这样就不会出错了。但是这个挖坑法的本质还是和hoare版本的快排是一样的,只不过实现的方式不同。


二、如何实现挖坑法?


动图演示如下:



参考代码:


void Swap(int* a, int* b)
{
  int tmp = *a;
  *a = *b;
  *b = tmp;
}
//三数取中
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 InsertSort(int* a, int n)
{
  assert(a);
  int i = 0;
  int end = 0;
  int tmp = 0;
  for (i = 0; i < n - 1; i++)
  {
    end = i;
    tmp = a[end + 1];
    while (end >= 0)
    {
      if (tmp < a[end])
      {
        a[end + 1] = a[end];
        --end;
      }
      else
      {
        break;
      }
    }
    a[end + 1] = tmp;
  }
}
// 快速排序挖坑法
int PartSort2(int* a, int left, int right)
{
  //三数取中
  int mid = GetMidNumi(a, left, right);
  if (mid != left)
  {
    Swap(&a[mid], &a[left]);
  }
  //先保存最左边的作为key
  int key = a[left];
  //让最左边的位置作为坑
  int pit = left;
  while (left < right)
  {
    //右边找小
    while (left < right && a[right] >= key)
    {
      --right;
    }
    //找到比key小的就填到坑里
    a[pit] = a[right];
    //让right变为新的坑
    pit = right;
    //左边找大
    while (left < right && a[left] <= key)
    {
      ++left;
    }
    //左边找到比key大的就填到右边的坑里
    a[pit] = a[left];
    //让left位置变为新的坑
    pit = left;
  }
  //最后把key填到坑里面(即相遇的位置)
  a[pit] = key;
  //返回坑的位置作为下一次递归排序的分界点
  return pit;
}
void QuickSort(int* a, int left,int right)
{
  assert(a);
  //区间只有一个值或者区间不存在就不用再递归下去了
  if (left >= right)
  {
    return;
  }
  //这里进行一个小区间优化,当一个区间<=10个元素的时候
  //快排已经不再适合,因为快排是数据越多并且越乱的时候
  //才是越快的,但是数据量小的时候,快排是没有很大的优势
  // 的如果这个是一个大数组经过多次递归下来的小区间,证明
  // 这个区间接近于有序的,此时换成直接插入排序会更加的高效
  if (right - left + 1 < 10)
  {
    InsertSort(a + left, right + 1 - left);
  }
  else
  {
    //每一趟快排之后都返回keyi的位置,把区间分成
    //[left,keyi-1][keyi][keyi+1,right]三个部分
    //再对子区间的数组进行快排,直到不满足递归条件再返回
    int keyi = PartSort3(a, left, right);
    QuickSort(a, left, keyi - 1);
    QuickSort(a, keyi + 1, right);
  }
}


三、挖坑法的时间复杂度是多少?


这个挖坑法的时间复杂度也是O(N*logN),证明如下:


相关文章
|
人工智能 JSON 安全
AI提示词入门教程
前言 在当前的信息时代,人工智能(AI)已成为我们日常生活和工作中不可或缺的一部分。尤其是在处理语言和文本的应用中,AI的效率和能力已经展现出巨大潜力。然而,要充分利用AI的能力,有效地与之交互是关键。本文旨在探讨如何通过合适的提示词来指导AI,以确保任务的准确性和效率。我们将重点讨论基本原则和技巧,这些内容对于任何希望通过AI实现特定目标的用户都是极其有用的。
1087 0
VScode修改打开默认编码及自动匹配文件编码格式
VScode修改打开默认编码及自动匹配文件编码格式
4833 0
VScode修改打开默认编码及自动匹配文件编码格式
|
存储 安全 算法
|
SQL 缓存 关系型数据库
API 接口性能优化管理
本文探讨了国内项目中常见的接口性能问题及其优化策略。面对紧张的工期与多样的编码习惯,文章系统地分析了性能需求、确立了性能标准,并详细列举了常见的性能瓶颈,如循环调用数据库、不当的SQL编写及数据处理方式等。针对这些问题,提出了包括配置调整、代码改进、数据库优化、引入缓存机制、利用异步处理等在内的多种解决方案,并强调了可观测性工具的重要性。通过这些方法,能有效提升接口性能和用户体验。
|
机器学习/深度学习 数据采集 算法
Python实现Catboost回归模型(CatBoostRegressor算法)项目实战
Python实现Catboost回归模型(CatBoostRegressor算法)项目实战
|
搜索推荐 算法 索引
【排序算法】深入解析快速排序(霍尔法&&三指针法&&挖坑法&&优化随机选key&&中位数法&&小区间法&&非递归版本)
【排序算法】深入解析快速排序(霍尔法&&三指针法&&挖坑法&&优化随机选key&&中位数法&&小区间法&&非递归版本)
466 4
|
移动开发 JSON 前端开发
|
存储 机器学习/深度学习 人工智能
未来已来:AI技术的最新趋势与前沿探索
【7月更文第20天】在这个日新月异的时代,人工智能(AI)已经从科幻概念逐渐深入到我们日常生活的方方面面,其发展速度之快超乎想象。从基础的语音识别、图像分析到复杂的决策制定、自动驾驶,AI技术正以前所未有的力量推动着社会进步。本文将带您一同展望AI技术的未来发展方向,深入探讨量子计算、生物计算等新兴领域的前沿探索,以及它们如何重新定义AI的边界。
732 0
|
缓存 并行计算 负载均衡
大模型推理优化实践:KV cache复用与投机采样
在本文中,我们将详细介绍两种在业务中实践的优化策略:多轮对话间的 KV cache 复用技术和投机采样方法。我们会细致探讨这些策略的应用场景、框架实现,并分享一些实现时的关键技巧。
|
SQL HIVE
Hive中日期处理函数的使用(date_format、date_add、date_sub、next_day)
Hive中日期处理函数的使用(date_format、date_add、date_sub、next_day)
3329 3