14

前序

说到排序算法,应该算是家喻户晓,人人皆知的大路货了。但是往往这些为人所熟知的东西中,也存在一些可以令人琢磨的细节。

这不,某天深夜,无所事事,大概是太寂寞,在思念了一番妹子以后,脑子里突然闪过了快速排序,遂在脑子中模拟了一遍快速排序的运行过程,以前只是死记硬背代码,没有去探究其运作的流程,于是在一些细节处陷入了沉思和迷惑,导致脑回路短路,当场打开斗鱼看了会球。

首先大家都知道,快排主要有两部分,分段(Partition)和递归(Recursive)。分段既将一组数据相对一个参考值分为两段,左段比参考值小,右端比参考值大,然后再递归对这两段进行分段。那么快排的关键部分自然就是这个分段算法,有了分段算法,加上递归,一个快排算法就写好了。

当然别小看了这个分段算法,是需要好好琢磨一番的。主要是一些临界值和极端情况的考虑,我的迷惑便是于此。于是查找了一些书籍和网络资源,加上自己的思路,总结了四种不同的分段算法。细节控可以来好好感受一下。

一. 填坑法

之所以叫填坑法,是其运作过程就像填坑一样。而且一点都不坑,代码形式非常好理解。

图片描述

代码如下:

int partition(int a[], int start, int end){
 int p = a[start];
 while(start < end){
 while(a[end] >= p && start < end) end--;
 a[start] = a[end];
 while(a[start] < p && start < end) start++;
 a[end] = a[start];
 }
 a[start] = p;
 return start;
}
void qs(int a[], int start, int end){
 if(start >= end){
 return;
 }
 int mid = partition(a, start, end);
 qs(a, start, mid-1);
 qs(a, mid+1, end);
}

二. 交换法

交换法,顾名思义就是要对两边的元素进行交换,再代码形式中用到swap函数。其流程如下:

图片描述

代码如下:

void swap(int* a, int* b){
 int temp = *a;
 *a = *b;
 *b = temp;
}
int partition(int a[], int start, int end){
 int pivot = a[start];
 int p = start+1;
 int q = end;
 while(p <= q){
 while(a[p] < pivot && p <= q) p++;
 while(a[q] >= pivot && p <= q) q--;
 if(p < q){
 swap(&a[p], &a[q]);
 }
 }
 swap(&a[start], &a[q]);
 return q;
}
void qs(int a[], int start, int end){
 if(start >= end){
 return;
 }
 int mid = partition(a, start, end);
 qs(a, start, mid-1);
 qs(a, mid+1, end);
}

可以看出这个方法和第二个方法有什么不同的地方,为什么要选第二个元素为start

三. 顺序遍历法

上面两种方法是维护了一个start,一个end指针,逐步向中间趋近的过程。而顺序遍历用一次遍历完成对数据的分段。

图片描述

代码如下:

void swap(int* a, int* b){
 int temp = *a;
 *a = *b;
 *b = temp;
}
int partition(int a[], int start, int end){
 int pivot = a[end];
 int storeIndex = start;
 for(int i = start; i < end; i++){
 if(a[i] < pivot){
 swap(&a[storeIndex], &a[i]);
 storeIndex++;
 }
 }
 swap(&a[storeIndex], &a[end]);
 return storeIndex;
}
void qs(int a[], int start, int end){
 if(start >= end){
 return;
 }
 int mid = partition(a, start, end);
 qs(a, start, mid-1);
 qs(a, mid+1, end);
}

四. 另类交换法

这个方法和之前的交换法的思路相同,但是它不返回mid值,所以索性称之为另类交换法吧。运作的流程就不做解释,直接上代码,各位客官姑且一看。

void qs(int a[], int start, int end){
 if(start >= end){
 return;
 }
 int pivot = a[start];
 int p = start;
 int q = end;
 while(1){
 while(a[p] < pivot) p++;
 while(a[q] > pivot) q--;
 if(p >= q){
 break;
 }
 swap(&a[p], &a[q]);
 p++;
 q--;
 }
 qs(a, start, p-1);
 qs(a, q+1, end);
}

后记

这四种算法用了四种不同的解决问题的思路,虽然都是细节上的不同,但是细细去想一下也能领会其中到奥妙。第一次在sf上发文章,也是为了巩固和牢记自己这么多天琢磨的东西。如果有什么错误和不足,也请各位看客多多指正和补充。


leeif
458 声望41 粉丝

前日本打工人,bytedancer,现在微软搬砖,沉迷chatgpt中。


« 上一篇

引用和评论

推荐阅读
头像
[Golang] 聊一聊Go的那些处理命令行参数和配置文件的库

leeif赞 2阅读 12.2k

头像
专题:2025年游戏市场洞察报告:市场规模、用户行为、投资趋势|附320+份报告PDF、数据、可视化模板汇总下载

拓端tecdat阅读 3.5k

头像
专题:2025AI产业全景洞察报告:企业应用、技术突破与市场机遇|附920+份报告PDF、数据、可视化模板汇总下载

拓端tecdat阅读 3.1k

头像
2025全球生成式人工智能AIGC产业全景与行业应用研究报告|附900+份报告PDF、数据、可视化模板汇总下载

拓端tecdat阅读 2.5k

头像
专题:2025年医疗健康行业状况报告:投融资、脑机接口、AI担忧|附130+份报告PDF合集、图表下载

拓端tecdat阅读 2.5k

头像
专题:2025年AI Agent智能体行业价值及应用分析报告:核心趋势、经济影响与治理框架|附700+份报告PDF

拓端tecdat阅读 2.4k

头像
大模型 | VLA 初识及在自动驾驶场景中的应用

地平线智驾开发者赞 1阅读 876

0 条评论
评论支持部分 Markdown 语法:**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用 @ 来通知其他用户。

AltStyle によって変換されたページ (->オリジナル) /