【数据结构与算法】快速排序的三种实现方法

简介: 【数据结构与算法】快速排序的三种实现方法

一.基本思想

任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

二.Hoare法

假设我们让最左边为keyi(注意这个表示的是下标),且要排升序;

1.若最左边为keyi,则right先走,找比arr[keyi]小的,left后走,找比arr[keyi]大的,然后right与left交换;

  当left和right相遇时,结束循环,最后交换arr[keyi]和arr[left]

  再让keyi=left,接着递归它的左子列和右子列

2.若最右边为keyi,则left先走,找比arr[keyi]大的,right后走,找比arr[keyi]小的,然后right与left交换

  当left和right相遇时,结束循环,最后交换arr[keyi]和arr[left]

  再让keyi=right,接着递归它的左子列和右子列

注意这里的keyi,left,right都是下标

左子列的区间是begin到keyi-1

右子列的区间是keyi+1到end

 

动态演示

 

1. void QuickSort(int* arr, int left,int right)
2. {
3. 
4.  if (left >= right)
5.    return;
6.  int begain = left;
7.  int end = right;
8.  int keyi= left;
9.  while (left < right)
10.   {
11. //这里要先判断left<right,防止越界,下同
12.     while (left<right && arr[right]>=arr[keyi])   //找小
13.     {
14.       right--;
15.     }
16. 
17.     while (left < right && arr[left] <= arr[keyi])  //找大
18.     {
19.       left++;
20.     }
21. 
22.     Swap(&arr[left], &arr[right]);   //交换
23.   }
24. 
25.   Swap(&arr[keyi], &arr[left]);
26.   keyi = left;
27. 
28.   QuickSort(arr, begain, keyi-1);   //递归左子列
29.   QuickSort(arr, keyi+1, end);      //递归右子列
30. }

三.挖坑法

动态演示

上面的Hoare法有很多坑,一不注意就容易写错,而挖坑法就没那么多坑了。

这个方法需要定义一个坑变量(hole),前面的Hoare法是交换两个元素,挖坑法是把值赋给坑位,然后更新一下坑位 。

1. void QuickSort(int* arr, int left, int right)
2. {
3. 
4.  if (left >= right)
5.    return;
6.  int begain = left;
7.  int end = right;
8.  int keyi = left;
9.  int hole = left;   //坑变量
10.   while (left < right)
11.   {
12.     while (left < right && arr[right] >= arr[leyi])   //找小
13.     {
14.       right--;
15.     }
16.     arr[hole] = arr[right];   //赋值给坑位
17.     hole = right;   //更新坑位
18.     while (left < right && arr[left] <= arr[keyi])   //找大
19.     {
20.       left++;
21.     }
22. 
23.     arr[hole] = arr[left];
24.     hole = left;
25.   }
26. 
27.   arr[hole] = key;
28.   keyi = left;
29. //递归左右子列
30.   QuickSort(arr, begain, hole - 1);
31.   QuickSort(arr, hole + 1, end);
32. }

四.前后指针法

动态演示

这个方法可以说是实现快速排序最常用的方法了。

1.定义一个prev和cur,它们都表示数组的下标,当然你定义成指针也没问题,这里以下标为例;

2.cur=prev+1

 注意:

          a.prev要么紧跟着cur,即prev的下一个就是cur;

          b.prev跟cur中间隔着比key大的一段值区间;

3.cur找到比key小的值,prev++,cur和prev位置互换,cur++

4.cur找到比key大的值,cur++

5.当cur>right时结束循环

1. void QuickSort(int* arr, int left, int right)
2. {
3.  if (left >= right)
4.    return;
5.  int begin = left, end = right;
6.  int prev = left, cur = left + 1;
7. 
8.  int keyi = left;
9.  while (cur <= right)
10.   {
11.     if (arr[cur] < arr[keyi])   
12.     {
13.       prev++;
14.       Swap(&arr[cur], &arr[prev]);
15.       cur++;
16.     }
17. 
18.     while (arr[cur] > arr[keyi])
19.     {
20.       cur++;
21.     }
22.   }
23.   Swap(&arr[keyi], &arr[prev]);
24.   keyi = prev;
25.   QuickSort(arr, begin, keyi - 1);
26.   QuickSort(arr, keyi + 1, end);
27. }

五.快速排序优化

在面对有序或是接近有序的情况下,快速排序的效率不高,是O(N^2),那要怎么解决这个问题呢?

 

既然对有序或是接近有序的不行,那我们就打乱它的顺序,这里有两种方法:

1.通过生成区间内的随机下标,让keyi与randi的数据交换,这样就打乱了原来的顺序;

2.三路取中法。

随机下标交换法

1. int randi = left + rand() % (right - left);   //随机key
2. Swap(&arr[keyi], &arr[randi]);

三路取中法

1. int GetMid(Sdatatype* arr, int left, int right)
2. {
3.  int mid = (left + right) / 2;
4.  if (arr[left] < arr[mid])
5.  {
6.    if (arr[mid] < arr[right])
7.      return mid;
8.    else if (arr[right] < arr[left])
9.      return left;
10.     else
11.       return right;
12.   }
13.   else  //arr[left]>arr[mid]
14.   {
15.     if (arr[right] < arr[mid])
16.       return mid;
17.     else if (arr[right] > arr[left])
18.       return left;
19.     else
20.       return right;
21. 
22.   }
23. 
24. }
25. 
26.   if (left != midi)
27.     Swap(&arr[left], &arr[midi]);

六.快速排序的特性

1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)

4. 稳定性:不稳定


🐬🤖本篇文章到此就结束了,若有错误或是建议的话,欢迎小伙伴们指出;🕊️👻

😄😆希望小伙伴们能支持支持博主啊,你们的支持对我很重要哦;🥰🤩

😍😁谢谢你的阅读。😸😼


目录
相关文章
|
29天前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
97 4
|
1月前
|
搜索推荐 C语言
【排序算法】快速排序升级版--三路快排详解 + 实现(c语言)
本文介绍了快速排序的升级版——三路快排。传统快速排序在处理大量相同元素时效率较低,而三路快排通过将数组分为三部分(小于、等于、大于基准值)来优化这一问题。文章详细讲解了三路快排的实现步骤,并提供了完整的代码示例。
57 4
|
2月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
56 3
|
27天前
|
存储 搜索推荐 Python
用 Python 实现快速排序算法。
快速排序的平均时间复杂度为$O(nlogn)$,空间复杂度为$O(logn)$。它在大多数情况下表现良好,但在某些特殊情况下可能会退化为最坏情况,时间复杂度为$O(n^2)$。你可以根据实际需求对代码进行调整和修改,或者尝试使用其他优化策略来提高快速排序的性能
118 61
|
27天前
|
存储 算法 安全
SnowflakeIdGenerator-雪花算法id生成方法
SnowflakeIdGenerator-雪花算法id生成方法
23 1
|
1月前
|
JSON 算法 数据挖掘
基于图论算法有向图PageRank与无向图Louvain算法构建指令的方式方法 用于支撑qwen agent中的统计相关组件
利用图序列进行数据解读,主要包括节点序列分析、边序列分析以及结合节点和边序列的综合分析。节点序列分析涉及节点度分析(如入度、出度、度中心性)、节点属性分析(如品牌、价格等属性的分布与聚类)、节点标签分析(如不同标签的分布及标签间的关联)。边序列分析则关注边的权重分析(如关联强度)、边的类型分析(如管理、协作等关系)及路径分析(如最短路径计算)。结合节点和边序列的分析,如子图挖掘和图的动态分析,可以帮助深入理解图的结构和功能。例如,通过子图挖掘可以发现具有特定结构的子图,而图的动态分析则能揭示图随时间的变化趋势。这些分析方法结合使用,能够从多个角度全面解读图谱数据,为决策提供有力支持。
|
2月前
|
Java C++ 索引
让星星⭐月亮告诉你,LinkedList和ArrayList底层数据结构及方法源码说明
`LinkedList` 和 `ArrayList` 是 Java 中两种常见的列表实现。`LinkedList` 基于双向链表,适合频繁的插入和删除操作,但按索引访问元素效率较低。`ArrayList` 基于动态数组,支持快速随机访问,但在中间位置插入或删除元素时性能较差。两者均实现了 `List` 接口,`LinkedList` 还额外实现了 `Deque` 接口,提供了更多队列操作。
30 3
|
2月前
|
算法 索引
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。
48 2
|
2月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
37 1
|
2月前
|
存储 算法 Java
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
前缀(波兰)表达式、中缀表达式和后缀(逆波兰)表达式的基本概念、计算机求值方法,以及如何将中缀表达式转换为后缀表达式,并提供了相应的Java代码实现和测试结果。
134 0
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现

热门文章

最新文章

  • 1
    2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
    30
  • 2
    2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    27
  • 3
    2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    29
  • 4
    2024重生之回溯数据结构与算法系列学习(8)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    31
  • 5
    2024重生之回溯数据结构与算法系列学习之王道第2.3章节之线性表精题汇总二(5)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    25
  • 6
    2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    39
  • 7
    2024重生之回溯数据结构与算法系列学习之顺序表习题精讲【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    26
  • 8
    2024重生之回溯数据结构与算法系列学习之顺序表【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    33
  • 9
    2024重生之回溯数据结构与算法系列学习【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
    25
  • 10
    数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
    95