快速排序是一种高效的分治排序算法,核心思想是通过选定基准元素将数组划分为两部分,递归排序子数组。本文详细介绍四种实现方式:Hoare法、挖坑法、前后指针法及非递归实现,并分析其优缺点。
实现步骤:
int PartSort1(int* a, int left, int right) {
int key = left;
while (left < right) {
while (left < right && a[right] >= a[key]) right--;
while (left < right && a[left] <= a[key]) left++;
swap(&a[right], &a[left]);
}
swap(&a[key], &a[left]);
return left;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
int keyi = PartSort1(a, left, right);
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
有没有发现什么端倪呢?😜
当基点每轮都是最大或者最小的元素时,性能会大幅下降,时间复杂度来到了
也就是说,会递归N次。
画图我们可以发现,这个递归的逻辑实际上就是一颗二叉树。
学过二叉树的我们知道,二叉树随着层数的增加,结点成指数增长,二叉树的最后一层的结点甚至占总结点数的一半,也就是说,递归的深度越大,递归的代价会越来越高。那么,有什么改进的办法呢?
核心思想:避免基点最大或最小
srand((unsigned int)time(NULL));
int randi = left + rand() % (right - left);
swap(&a[left], &a[randi]);
int key = left;
//三数取中
int GetMidNumi(int* a, int left, int right)
{
int mid = (left + right) / 2;
if (a[mid] > a[left]) {
if (a[left] > a[right]) {
return left;
}
else if (a[mid] < a[right]) {
return mid;
}
else {
return right;
}
}
else {
if (a[left] < a[right]) {
return left;
}
else if (a[mid] > a[right]) {
return mid;
}
else {
return right;
}
}
}
int main()
{
int mid = GetMidNumi(a, left, right);
if (mid != left)
swap(&a[left], &a[mid]);
int key = left;
}
💡:三数取中法的效果略高于随机定数,因为随机定数依然有概率选到最大最小数(尽管这可能是极小概率事件)
后文选取基点均用三数取中法。
递归的最后几层不再进行递归,直接用插入排序即可
插入排序不再赘述【初探数据结构】直接插入排序与希尔排序详解
if ((right - left + 1) > 10) {
int keyi = PartSort1(a, left, right);
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
else
InsertSort(a+left,(right-left+1));
正确代码:
// 快速排序hoare版本
int PartSort1(int* a, int left, int right)
{
//随机数定key
/*srand((unsigned int)time(NULL));
int randi = left + rand() % (right - left);
swap(&a[left], &a[randi]);*/
//三数选中定key(效果相比随机法相对较高)
int mid = GetMidNumi(a, left, right);
if (mid != left)
swap(&a[left], &a[mid]);
int key = left;
while (left < right)
{
//right先走
//right向左找小
while (left < right && a[right] >= a[key])
{
right--;
}
//left向右找大
while (left < right && a[left] <= a[key])
{
left++;
}
swap(&a[right], &a[left]);
}
swap(&a[key], &a[left]);
key = left;
return key;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
//区间优化
if ((right - left + 1) > 10) {
int keyi = PartSort1(a, left, right);
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
else
InsertSort(a+left,(right-left+1));
}
实现步骤:
代码要点:
int PartSort2(int* a, int left, int right) {
int mid = GetMidNumi(a, left, right);
if (mid != left)
swap(&a[left], &a[mid]);
int key = a[left], hole = left;
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;
}
优点:减少元素交换次数,逻辑更直观。
实现步骤:
prev
指向基准位置,cur
从prev+1
开始遍历。cur
指向的元素小于基准,prev
先右移,再交换prev
和cur
的元素。prev
位置的元素交换。代码要点:
int PartSort3(int* a, int left, int right) {
int mid = GetMidNumi(a, left, right);
if (mid != left) swap(&a[left], &a[mid]);
int key = left, cur = left + 1, prev = left;
while (cur <= right) {
if (a[cur] < a[key] && ++prev != cur)
swap(&a[prev], &a[cur]);
cur++;
}
swap(&a[prev], &a[key]);
return prev;
}
优点:代码简洁,适合单链表排序。
实现步骤:
[left, right]
压入栈。代码要点:
void QuickSortNonR(int* a, int left, int right) {
ST st;
STInit(&st);
STPush(&st, right); // 先压右边界
STPush(&st, left); // 再压左边界
while (!STEmpty(&st)) {
int begin = STTop(&st); STPop(&st);
int end = STTop(&st); STPop(&st);
if (begin < end) {
int keyi = PartSort3(a, begin, end);
// 压入右子区间
STPush(&st, end);
STPush(&st, keyi + 1);
// 压入左子区间
STPush(&st, keyi - 1);
STPush(&st, begin);
}
}
STDestroy(&st);
}
注意事项:
右子右界→右子左界→左子右界→左子左界
。Push
和Pop
操作符合后进先出(LIFO)特性。方法 | 优点 | 缺点 |
---|---|---|
Hoare法 | 经典实现,易于理解 | 需注意指针移动顺序 |
挖坑法 | 减少交换次数,逻辑清晰 | 代码稍复杂 |
前后指针 | 代码简洁,适合单链表 | 指针移动需仔细理解 |
非递归 | 避免栈溢出,适合大数据量 | 需手动管理栈,调试复杂 |
优化策略:
(right-left+1) > 10
时优化)。快速排序时间复杂度
快速排序的四种实现方式各有适用场景:
理解每种方法的核心逻辑和细节,才能在实际应用中灵活选择最优方案。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有