快速排序算法详解:Hoare法、挖坑法、前后指针法及非递归实现
创作时间:
作者:
@小白创作中心
快速排序算法详解:Hoare法、挖坑法、前后指针法及非递归实现
引用
CSDN
1.
https://m.blog.csdn.net/weixin_64099089/article/details/137792497
**快速排序是一种非常高效的排序算法,由C. A. R. Hoare在1960年提出。它采用分治法策略,通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录继续进行排序,以达到整个序列有序的目的。本文将详细介绍快速排序的多种实现方式,包括Hoare法、挖坑法、前后指针法以及非递归实现(栈和队列)。
1. Hoare法
快速排序的核心思想是选择一个基准元素(通常选择序列的第一个元素),通过一趟排序将待排序的记录分割成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
单趟排序步骤:
- 选定一个基准元素(key),初始化左右指针L和R
- R从右向左查找比key小的元素
- L从左向右查找比key大的元素
- 交换L和R位置的元素
- 重复步骤2-4,直到L和R相遇
- 最后将基准元素与相遇位置的元素交换
单趟排序的意义:
- 基准元素被放置到正确的位置
- 将序列分割成两个子区间,左侧元素都小于基准元素,右侧元素都大于基准元素
单趟排序实现:
void PartSort(int* a, int begin, int end) {
if (begin >= end)
return;
int keyi = begin;
int key = a[keyi];
int Left = begin;
int Right = end;
while (Left < Right) {
while (Left < Right && a[Right] >= key)
Right--;
while (Left < Right && a[Left] <= key)
Left++;
Swap(&a[Left], &a[Right]);
}
Swap(&a[keyi], &a[Left]);
}
快速排序递归实现:
void QuickSort(int *a, int begin, int end) {
assert(a);
if (begin >= end)
return;
int meet = PartSort(a, begin, end);
QuickSort(a, begin, meet - 1);
QuickSort(a, meet + 1, end);
}
2. 挖坑法
挖坑法是快速排序的另一种实现方式,其核心思想是通过"挖坑填数"的方式进行元素交换,可以减少代码中的边界条件判断,使代码更加简洁。
单趟排序步骤:
- 选择一个基准元素(key),将其位置设为"坑"
- R从右向左查找比key小的元素,找到后填入"坑"中,当前位置变成新的"坑"
- L从左向右查找比key大的元素,找到后填入"坑"中,当前位置变成新的"坑"
- 重复步骤2-3,直到L和R相遇
- 最后将基准元素填入相遇位置的"坑"中
单趟排序实现:
int QuickPastSort2(int* a, int begin, int end) {
assert(a);
int keyi = GetMidIndex(a, begin, end);
int key = a[keyi];
Swap(&a[keyi], &a[begin]);
keyi = begin;
int hole = begin;
int left = begin;
int right = end;
while (left < right) {
while (left < right && a[right] >= key)
right--;
a[hole] = a[right];
hole = right;
while (left < right && a[left] <= key)
left++;
a[hole] = a[left];
hole = left;
}
a[hole] = key;
return hole;
}
3. 前后指针法
前后指针法是快速排序的另一种实现方式,其核心思想是使用两个指针(prev和cur)进行元素交换,可以进一步简化代码逻辑。
单趟排序步骤:
- 初始化prev指向基准元素,cur指向基准元素的下一个位置
- prev和cur同时向前移动,直到prev的下一个位置是比基准元素大的数
- prev停在比基准元素大的数前面,cur继续向后查找比基准元素小的数
- cur找到比基准元素小的值后,prev先++,然后prev和cur位置的数交换
- 最后cur越界时,key与prev指向的位置交换
单趟排序实现:
int QuickPartSort3(int* a, int begin, int end) {
assert(a);
int keyi = GetMidIndex(a, begin, end);
Swap(&a[keyi], &a[begin]);
int key = a[begin];
keyi = begin;
int prev = begin;
int cur = begin + 1;
while (cur <= end) {
if (a[cur] < key && ++prev != cur)
Swap(&a[cur], &a[prev]);
cur++;
}
Swap(&a[begin], &a[prev]);
return prev;
}
4. 快排的非递归实现
快速排序的递归实现可能会导致栈溢出问题,特别是在数据量较大时。因此,可以使用栈或队列来实现非递归版本的快速排序。
4.1 栈实现快排非递归
使用栈实现非递归快速排序时,可以按照前序遍历的顺序,先处理左子区间,再处理右子区间。
void StackQuickSort(int* a, int n) {
assert(a);
ST st;
STInit(&st);
StackPush(&st, n - 1);
StackPush(&st, 0);
while (!StackEmpty(&st)) {
int begin = StackTop(&st);
StackPop(&st);
int end = StackTop(&st);
StackPop(&st);
if (begin >= end)
continue;
int meet = QuickPastSort1(a, begin, end);
StackPush(&st, end);
StackPush(&st, meet + 1);
StackPush(&st, meet - 1);
StackPush(&st, begin);
}
STDestroy(&st);
}
4.2 队列实现快排非递归
使用队列实现非递归快速排序时,可以按照层序遍历的顺序,依次处理每个子区间。
void QueueQuickSort(int* a, int n) {
assert(a);
Queue q;
QueueInit(&q);
QueuePush(&q, 0);
QueuePush(&q, n - 1);
while (!QueueEmpty(&q)) {
int begin = QueueFront(&q);
QueuePop(&q);
int end = QueueFront(&q);
QueuePop(&q);
if (begin >= end)
continue;
int meet = QuickPastSort1(a, begin, end);
QueuePush(&q, begin);
QueuePush(&q, meet - 1);
QueuePush(&q, meet + 1);
QueuePush(&q, end);
}
QueueDestroy(&q);
}
使用栈和队列实现非递归快速排序时,空间复杂度为O(1),但在实际应用中,递归实现更为简洁和方便。
热门推荐
闵行区三重利好消息:教育资源升级,新社区亮相,交通建设快马加鞭!
如何科学选择编程语言:六大维度全面解析
软件系统工作量估算方法论介绍——功能点分析法
宇宙起源方式或将被改写?诺奖得主:宇宙正在循环,我有关键证据
指责、批评、谴责:探究表达不满的语言艺术
健身圈传来噩耗,35岁健身网红突然离世,原因还是它!
鱼油和磷虾油哪个吃哪种最好
皇姑区小学集团化办学改革方案发布 不断推进家门口从“有学上”到“上好学”
湖人大战凯尔特人 伤病名单 詹姆斯东契奇大概率出战 绿军多人复出
深入探究:如何使用服务器数量计算公式?
NASA GRX-810新超级合金3D打印火箭发动机成功测试
收入再少也能存钱!适合理财新手的6个超简单存钱方法,助你稳定累积财富!
荔枝的品种分类
美国海军11艘核动力航母最新动态:位置、状态全解析
战机出动效率,辽宁舰和山东舰,对比欧美,到底什么档次?
单位拖欠工资申请仲裁程序是哪些
耳鸣的常见诱因和缓解策略
白蚁防治,你真的知道怎么做吗?一文为你解答!
高纯度锶盐市场专项深度调研报告
痛风发作真要命!205种高嘌呤食物清单,一定要知道!
导热硅胶片在显卡散热中的关键应用
汽车轮胎没气了还能开吗?普通胎与防爆胎的区别
个人防护装备:了解与选择的科学指南
考研关键期,2025年在职研究生复试该如何准备?
一文解读:血液灌流的适应证与禁忌证
肠炎的全面解析:症状、危害与防治指南
宝宝1岁大便稀吃什么好
鸡鸭吃哪种牧草好 用它们喂养都很合适
武汉从土里“种出”天然气!超级芦竹投入运用,或掀起新能源革命
高寒地区驾驶人必读:雪地胎更换全攻略