Go实现的分治排序代码是快速排序还是归并排序?
算法类型判定结论
你写的是快速排序的非原地朴素三路实现,不属于归并排序。
判定依据
快排和归并排序虽然都用了分治思路,但核心逻辑差异非常明显,和是否做原地元素交换没有必然联系:
- 快速排序的核心流程是:先选定基准元素(pivot),遍历数组将元素按和基准的大小关系拆分到不同分区(小于基准、等于基准、大于基准),之后递归排序小于、大于基准的两个分区,最后直接按顺序拼接所有分区就能得到有序数组。分区动作完成时,左分区所有元素和右分区所有元素已经满足跨区间的大小顺序,拼接阶段不需要做任何元素大小比对。
- 归并排序的核心流程是:先将数组从中间对半拆成两个长度尽可能相等的子数组,递归拆分直到子数组长度为1,再从最小粒度开始,通过双指针逐元素比对两个已经有序的子数组,按大小顺序合并成更大的有序数组。整个流程不存在「选基准、按基准大小拆分分区」的步骤,核心开销集中在合并阶段的元素比对上。
对照你的代码逻辑:你固定选择索引0的元素作为pivot,遍历数组时按元素和pivot的大小关系拆分到三个切片,递归排序左右分区后直接通过append拼接结果,完全没有归并排序必须的「双指针逐元素比对合并两个有序数组」的环节,完全符合快速排序的定义。
你提到的「快排必须实现原地swap」是很常见的认知误区:原地交换的分区实现(比如Lomuto分区、Hoare分区)只是快排的空间优化版本,目的是把额外空间开销从O(n)降低到递归栈占用的O(logn)级别,并不是快排的必备特征。你现在这种额外开辟内存存储分区的写法,是入门教学中非常常见的快排简化实现,只是空间效率比原地版差而已。另外你把等于pivot的元素单独归到centerPivot分区的思路是合理的,这就是三路快排的核心优化点,能大幅提升重复元素较多场景下的排序效率,避免相等元素被重复递归处理。
代码改进建议
- 优化pivot选择逻辑:目前你固定选择数组第一个元素当pivot,如果输入数组本身是完全有序/完全逆序的,递归深度会退化成O(n),整体时间复杂度会从O(nlogn)掉到O(n²)。可以改成随机选pivot、或者三数取中(取首、尾、中间位置三个元素的中位数当pivot),规避最坏时间复杂度。
- 简化循环内的分支判断:现在你把升序/降序的判断写在了遍历循环内部,每次循环都会做一次无意义的分支判断,增加了不必要的开销。可以在循环外先确定大小比较规则,减少循环内的判断次数。
- 降低内存分配开销:目前每次递归都会新建三个切片,数据量较大时内存申请、拷贝的开销会很高。如果追求性能,可以改成原地分区的实现,仅通过左右索引标记当前处理的数组区间,复用原数组内存,空间效率会高很多。
内容的提问来源于stack exchange,提问作者SecurityNooblet
相关产品推荐
相关产品推荐

