7大排序算法-- 堆排 快速排序 --精解(下)

简介: 7大排序算法-- 堆排 快速排序 --精解(下)

🕳挖坑法:

挖坑法其实和hoare版本差不了太多 只是形式上有点差别

f563ce5c587344bab497e04f7b5fe138.gif

① 我们首先记录keyi的位置为 坑🕳

② 右边的先走(这里和hoare版本那里一样 先走的一方与keyi 相对) 找小 把数据填到 坑🕳 的位置上 让后当前小的数据(汽车)的位置设为新的 坑位🕳

③ 左边的再走 也是一样的道理 每次挪动数据 都要更新坑位🕳

④ 相遇的位置和坑的位置相同 坑的位置一直都在停留等待的那一方


 我们的 挖坑法🕳 与 hoare版本在 数据移动上 是不一样的 hoare版本是两个数据交换(使用swap函数) 我们的 挖坑法🕳 不一样的是 这个是覆盖 我们首先记录keyi的值 直到最后再把它放在它该有的位子


大家思考一下 这个和hoare版本哪一个会更好一点呢?

其实都差不多 哈哈哈 区别并不大 硬要说有什么区别的话 :可能就是我们的挖坑法更好理解了把 我们不用太去关心为什么相遇的位置该是keyi等等的问题

  我们只用知道 左边做keyi为坑🕳 那我们就应该找一个小的数放过去 所以我们右边的汽车先走找小填过去 此时的坑🕳更新为靠近右边的位置那我左边的摩托不就是要找个大的数填入过去嘛 最后相遇了 相遇了的位置左右两边 一边大 一边小 此时把keyi放进去不就正好满足条件了嘛 

    int keyi = a[left];
  int pit = left;
  while (left < right)
  {
    while (left < right && a[right] >= keyi)
    {
      right--;
    }
    a[pit] = a[right];
    pit = right;
    while (left < right && a[left] <= keyi)
    {
      left++;
    }
    a[pit] = a[left];
    pit = left;
  }
  a[pit] = keyi;

注意:两个版本的时间复杂度都是O(N)


前后指针法:

这个方法较之前的两种方法 可能有点难理解一些

770ff188dcce42da8dc3111c8170102d.gif

大家看明白这个动图了嘛 思路很简单:

① 我们的cur往前面走 找小

② 找到 ++prev 交换prev和cur的值

其实总的来讲就是我们把那些小的数往左边移动 大的数又往右边推  而夹在他们中间的数都是大于keyi的数

int PartSort3(int* a, int left, int right)
{
  int prev, cur;
  int keyi = left;
  prev = left;
  cur = left + 1;
  while (cur <= right)
  {
    if (a[cur] <= a[keyi] && a[++prev] != a[cur])//附加的判断条件 意思是我的prev和cur中
    {                                            //间得有值才让交换
      swap(a + prev, a + cur);
    }
    cur++;
  }
  swap(a + keyi, a + prev);
  return prev;
}

咋们这里的小于等于 可以没有 等于 因为相等的数 在左 在右 都是不影响的

咋们这里的限制条件: 只有小于了 并且++prev后不等于cur(就是prev不紧跟在cur后面) 才交换  就是不用自己交换自己了


如果你设置的keyi是在右边 那么我们cur就应该从第一个位置开始遍历 而prev是始终都在cur的前面的 所以 cur=left,prev=left-1;

遍历的时候最右边的数据作为 keyi 就不用去遍历它了 所以我们cur遍历到最后一个数据时 就可以结束了

还有一点要注意 我们cur与prev之间的是比keyi大的数 而keyi的位置又在右边是要放一个大的数 所以我们最后的 prev 还要再加加一次 这样才是一个大于keyi的数放过去


快排的时间复杂度:

我们这样快速排序的几个版本就说完了  现在我们来想想快排的时间复杂度 又会是多少呢?

dffd82091f624cf193d875b89f85eb11.png

最坏的情况其实还是存在的 就好像我们的现在的数组是已经有序的了 或者是接近有序的了 现在我们选择 最左 或 最右 的话就又可能选到 最大最小 的数了 而且这种最坏的情况是非常危险的 应为一旦数据过大 就会栈溢出了


那针对这种情况我们 该怎么解决呢 不然我们的快排在这方面就太拉了

其实很简单 就是改变我们选keyi的方式就可以了 我们之前是直接选择最左最右 现在我们不那么做了  我们再 左-中-右 选一个

    int tmp = CheckMidKey(a, (right - left + 1) >> 1, left, right);
    swap(a + left, a + tmp);

我们依旧还是选择左边做 keyi 只不过找到tmp 后把tmp的值和当前left的值换一下不就可以了嘛 此时left就是我们想要的数了

我们此时三数取中:

int CheckMidKey(int* a, int mid, int left, int right)
{
  if (a[mid] < a[right])
  {
    if (a[mid] > a[left])
    {
      return mid;
    }
    else if (a[right] < a[left])
    {
      return right;
    }
    else
    {
      return left;
    }
  }
  else//a[mid]>a[right]
  {
    if (a[mid] < a[left])
    {
      return mid;
    }
    else if (a[right] > a[left])
    {
      return right;
    }
    else
    {
      return left;
    }
  }
}


小区间优化:

对于快排的优化 还不止这一个

小区间优化: 就是当我们递归到数据已经不那么多的时候就不用递归了 直接用其他的排序来解决 因为我们数据很多时 我们递归可以很好的提高效率 毕竟时O(N*logN) 但是当我们数据变少了的时候 这个效率的提高就没那么明显了

好比我们现在一个区间只有5个数据了

91246843adde45b4a22a0e28a3374746.png

所以我们采用小区间优化的话 会消去很多次的递归调用

void QuickSort(int* a, int left, int right)
{
  if (left >= right) return;
  if (right - left + 1<= 10)
  {
    InsertSort(a + left, right - left + 1);
  }
  int keyi = PartSort2(a, left, right);
  QuickSort(a, left, keyi - 1);
  QuickSort(a, keyi + 1, right);
}

right-left 加1 是因为我们的left和 right 都是下标 下标是从0开始的所以加 1

我么的插入排序 的其实位置 是 a+left 因为区间又不一定是从头开始的 也可能是keyi右边的数 就是从当前 left 的位置开始的

目录
相关文章
|
1月前
|
搜索推荐 C语言
【排序算法】快速排序升级版--三路快排详解 + 实现(c语言)
本文介绍了快速排序的升级版——三路快排。传统快速排序在处理大量相同元素时效率较低,而三路快排通过将数组分为三部分(小于、等于、大于基准值)来优化这一问题。文章详细讲解了三路快排的实现步骤,并提供了完整的代码示例。
59 4
|
28天前
|
存储 搜索推荐 Python
用 Python 实现快速排序算法。
快速排序的平均时间复杂度为$O(nlogn)$,空间复杂度为$O(logn)$。它在大多数情况下表现良好,但在某些特殊情况下可能会退化为最坏情况,时间复杂度为$O(n^2)$。你可以根据实际需求对代码进行调整和修改,或者尝试使用其他优化策略来提高快速排序的性能
120 61
|
2月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
39 1
|
2月前
|
搜索推荐 Java Go
深入了解快速排序算法
深入了解快速排序算法
56 2
|
2月前
|
存储 搜索推荐 算法
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
【排序算法(二)】——冒泡排序、快速排序和归并排序—>深层解析
|
2月前
|
算法 Python
Python算法编程:冒泡排序、选择排序、快速排序
Python算法编程:冒泡排序、选择排序、快速排序
36 0
|
2月前
|
搜索推荐 C语言 C++
【C语言】指针篇-精通库中的快速排序算法:巧妙掌握技巧(4/5)
【C语言】指针篇-精通库中的快速排序算法:巧妙掌握技巧(4/5)
|
4月前
|
搜索推荐 算法 Java
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
该博客文章通过UML类图和Java源码示例,展示了如何使用适配器模式将QuickSort类和BinarySearch类的排序和查找功能适配到DataOperation接口中,实现算法的解耦和复用。
56 1
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
|
4月前
|
算法 搜索推荐
算法设计 (分治法应用实验报告)基于分治法的合并排序、快速排序、最近对问题
这篇文章是关于分治法应用的实验报告,详细介绍了如何利用分治法实现合并排序和快速排序算法,并探讨了使用分治法解决二维平面上的最近对问题的方法,包括伪代码、源代码实现及时间效率分析,并附有运行结果和小结。
|
5月前
|
算法 搜索推荐 编译器
算法高手养成记:Python快速排序的深度优化与实战案例分析
【7月更文挑战第11天】快速排序是编程基础,以O(n log n)时间复杂度和原址排序著称。其核心是“分而治之”,通过选择基准元素分割数组并递归排序两部分。优化包括:选择中位数作基准、尾递归优化、小数组用简单排序。以下是一个考虑优化的Python实现片段,展示了随机基准选择。通过实践和优化,能提升算法技能。**
66 3

热门文章

最新文章