Skip to content
← 返回算法列表
问题与数据结构

查找、排序与区间 ​

本页按场景选择方法;通过各条目链接阅读完整推演、源码和输出。

这些 package main 程序应分别保存到独立练习模块(Go 1.22+);本轮未运行。原地排序会改输入,归并/计数/桶排序返回新结果。数值和分配大小必须落在本机 int 与可用内存范围内,桶宽必须为正;无效输入的返回约定不替代生产 API 校验。

要解决的问题可选方法选择前确认
只查询少量或无序数据线性查找;有序输入才用二分查找二分答案还要求可行性单调且上下界覆盖解。
学习局部交换,或处理小数组、近乎有序数据冒泡排序、选择排序、插入排序、希尔排序插入最坏仍为 O(n²);选择排序不稳定,希尔性能取决于间隔序列。
需要保留相等元素的原顺序归并排序时间 O(n log n),需要 O(n) 合并空间。
比较平均性能与原地排序的时间上界快速排序或堆排序快排平均 O(n log n)、最坏 O(n²);堆排序原地且有 O(n log n) 上界,但不稳定。
已知整数值域、位数或数据分布计数排序、基数排序、桶排序计数和基数示例只处理非负整数;桶排序效果依赖分布和桶宽。
只保留最大的 k 个值Top K 最小堆时间 O(n log k);返回堆内部顺序,展示时可能还需排序。
安排最多活动、合并覆盖范围或降低文件合并成本区间调度、区间合并、最小代价合并分别按结束时间、起点和当前最小文件选择;端点是否冲突须按业务定义。

估算成本并选择查找方式 ​

时间与空间复杂度 ​

正文、推演与完整示例:时间与空间复杂度。

先确定 n 表示什么,再统计循环或递归会执行多少次。示例只遍历一次切片,所以输入翻倍时工作量大致翻倍;累计变量只占固定空间。 示例时间 O(n)、额外空间 O(1)。

复杂度描述的是增长趋势,常数开销和真实输入分布仍会影响性能。

线性查找 ​

正文、推演与完整示例:线性查找。

从头检查每个元素,第一次相等时返回下标。它不要求预处理或排序,数据很少或只查询一次时常是最简单的选择。 时间 O(n)。

若在同一大集合上反复查找,可以考虑排序后二分或建立哈希索引。

二分查找 ​

正文、推演与完整示例:二分查找。

维护一个可能包含目标值的半开区间 [l,r),根据中点与目标的比较缩小一侧。循环结束后还需检查候选下标是否真的匹配。 时间 O(log n)。

前提是输入按相同规则排序;否则二分的排除逻辑不成立。

二分答案 ​

正文、推演与完整示例:二分答案。

使用前要证明边界覆盖解,并防止不可行时把 hi 误当作有效答案。

从简单排序比较到归并、快排与堆排序 ​

插入排序 ​

正文、推演与完整示例:插入排序。

循环开始时,左侧前缀始终有序;当前值向左寻找位置,并把较大的元素右移。输入接近有序时移动次数很少,因此小数组或排序算法的收尾阶段常会采用它。 最坏时间 O(n²)。

完全逆序时仍需 O(n²) 次移动。

冒泡排序 ​

正文、推演与完整示例:冒泡排序。

真实项目通常直接使用 sort 包;该算法主要帮助理解局部交换与不变式。

选择排序 ​

正文、推演与完整示例:选择排序。

在未排序部分找到最小元素,与当前位置交换,然后缩小待处理范围。它始终需要二次方级比较,却只进行线性次数的交换。 时间 O(n²),交换次数 O(n)。

交换会改变相等元素的相对顺序,因此这个基本版本不稳定。

希尔排序 ​

正文、推演与完整示例:希尔排序。

它就地工作且代码不复杂,但最坏性能依赖所选间隔序列,通常不如标准库排序具有明确保证。

归并排序 ​

正文、推演与完整示例:归并排序。

递归把数组分成两半,分别排序后通过比较两边当前元素完成合并。合并时优先取左侧相等元素可保持稳定性。 时间 O(n log n)、额外空间 O(n)。

每层总工作为 O(n),层数为 O(log n);代价是需要额外的合并空间。

快速排序 ​

正文、推演与完整示例:快速排序。

选择一个基准值,用双指针把较小值移到左侧、较大值移到右侧,再分别递归。分区均衡时性能很好;若基准长期偏向一侧,递归深度和时间会恶化。 平均时间 O(n log n),最坏 O(n²)。

工程实现通常加入随机化或深度限制。

堆排序 ​

正文、推演与完整示例:堆排序。

先自底向上建立最大堆,根节点就是当前最大值。将根与末尾交换后缩小堆,再向下调整新的根,直到全部元素有序。 时间 O(n log n)、额外空间 O(1)。

它有稳定的 O(n log n) 时间上界且原地排序,但相等元素的顺序不保留。

利用值域、位数或分布减少比较 ​

计数排序 ​

正文、推演与完整示例:计数排序。

先统计每个整数值出现的次数,再按值域顺序写回结果。它不通过比较决定先后,因此在值域 k 较小时可优于比较排序。 时间 O(n+k)、空间 O(k),k 为值域大小。

示例只支持 0 到 maxValue 的非负整数;值域很大时计数数组会浪费内存。

基数排序 ​

正文、推演与完整示例:基数排序。

从个位开始,对每一位进行稳定的计数排序,让低位顺序在处理高位时得以保留。位数固定时可获得接近线性的性能。 时间 O(d(n+b)),d 为位数、b 为进制。

本例基数排序用 exp 表示当前十进制位的权重。处理完一轮后,exp > max/10 表示下一位已经超过最大输入的最高位,应立即退出;这样既避免无意义的继续排序,也防止 exp 乘十溢出。它只接受非负整数,负数需要另行编码。

示例采用十进制并只处理非负整数;负数或不同类型的键需要额外编码策略。

桶排序 ​

正文、推演与完整示例:桶排序。

根据值与最小值的距离把元素放进不同桶,每个桶内部排序后依次连接。效果依赖数据是否均匀分布以及桶宽是否合适。 分布较均匀时接近线性。

示例要求 bucketSize 大于零;所有值落入同一桶时优势会消失。

只筛选最大的 k 个值 ​

Top K ​

正文、推演与完整示例:Top K。

扫描元素时,堆中只保留目前最大的 k 个值,堆顶是这些值中最小的一个。新值若不大于堆顶即可跳过,否则替换堆顶。 时间 O(n log k)。

示例返回的是堆内部顺序,不保证有序;需要按大小展示时再排序输出。

安排区间与选择合并顺序 ​

区间调度 ​

正文、推演与完整示例:区间调度。

把活动按结束时间排序,优先选择最早结束且不与上一个活动冲突的区间。较早结束会给后续活动留下最多可用空间,这可用交换论证证明最优。 目标是最多可安排的活动数。

示例把区间视为允许端点相接;是否相接算冲突须按业务定义。

区间合并 ​

正文、推演与完整示例:区间合并。

按起点排序后,只需和当前合并区间比较:若重叠就扩展终点,否则把新区间放进结果。排序保证后续区间不可能回到已结束区间的左侧。 时间 O(n log n)。

示例会原地排序输入切片;若调用方需要保留原顺序,应先复制。

最小代价合并 ​

正文、推演与完整示例:最小代价合并。

示例反复排序,实际处理大量文件时可换成最小堆。

静态自检 ​

预测 RadixSort 对 {最大int,0,10} 的结果,以及最后一轮为何必须先判断再 exp*=10。提示:最后有效十进制位之后无需继续。

参考解法

应升序为 {0,10,最大int};当 exp > max/10 时已处理最高位,直接结束,避免下一次乘十溢出造成错误位数或异常循环。此结论为静态推导,修改后的示例未执行。

继续阅读