查找与排序算法:复杂度、稳定性

查找与排序算法:复杂度、稳定性

查找解决关键字定位,排序解决记录重排。算法选择不能只看平均时间复杂度,还要考虑数据是否有序、是否要求稳定、是否允许额外空间以及是否必须保证最坏性能。

顺序查找与折半查找

顺序查找逐项扫描,最好为 O(1),平均和最坏为 O(n),额外空间为 O(1)。哨兵可以减少边界判断,但不改变渐进复杂度。

折半查找要求序列有序,每轮将区间缩小一半:

cpp 复制代码
int left = 0, right = n - 1;
while (left <= right) {
    int mid = left + (right - left) / 2;
    if (a[mid] == key) return mid;
    if (a[mid] < key) left = mid + 1;
    else right = mid - 1;
}
return -1;

时间复杂度为 O(log n),空间复杂度为 O(1)。查找第一个或最后一个重复值时,命中后仍需继续收缩边界。

插入、折半插入与希尔排序

插入排序维护有序前缀,将当前元素插入正确位置。它稳定、原地,对近乎有序数据有效,平均和最坏为 O(n²)。

折半插入排序用二分查找减少比较次数,但数组移动仍为 O(n²),因此总体复杂度不变。

希尔排序按间隔 gap 进行分组插入排序,再逐步缩小间隔到 1。复杂度取决于增量序列,通常不稳定,但比直接插入排序更适合中等规模数据。

冒泡排序

冒泡排序交换相邻逆序元素。加入交换标志后,已经有序时可以提前结束:

cpp 复制代码
for (int end = n - 1; end > 0 && swapped; --end) {
    swapped = false;
    for (int i = 0; i < end; ++i) {
        if (a[i] > a[i + 1]) {
            std::swap(a[i], a[i + 1]);
            swapped = true;
        }
    }
}

最好为 O(n),平均和最坏为 O(n²),稳定且原地,但通常只适合小规模或教学场景。

快速排序

快速排序通过枢轴划分区间:

text 复制代码
partition(l, r)
quick_sort(l, pivot - 1)
quick_sort(pivot + 1, r)

平均复杂度为 O(n log n),最坏为 O(n²),平均递归空间为 O(log n)。随机枢轴、三路划分和小区间插入排序可以减少退化和常数开销。快速排序通常不稳定。

选择排序

选择排序每轮寻找未排序区间的最小元素并交换到前端。比较次数始终为 O(n²),交换次数较少,原地但不稳定。

堆排序

堆排序先建立大根堆,再将堆顶最大元素交换到末尾并恢复堆:

cpp 复制代码
for (int i = n / 2; i >= 1; --i) sift_down(i, n);
for (int end = n; end > 1; --end) {
    swap(a[1], a[end]);
    sift_down(1, end - 1);
}

建堆为 O(n),排序为 O(n log n),额外空间为 O(1),最坏复杂度有保证,但不稳定。

复杂度比较

算法 平均时间 最坏时间 空间 稳定性
顺序查找 O(n) O(n) O(1) -
折半查找 O(log n) O(log n) O(1) -
插入排序 O(n²) O(n²) O(1) 稳定
希尔排序 依增量序列 依增量序列 O(1) 通常不稳定
冒泡排序 O(n²) O(n²) O(1) 稳定
快速排序 O(n log n) O(n²) O(log n) 平均 不稳定
选择排序 O(n²) O(n²) O(1) 不稳定
堆排序 O(n log n) O(n log n) O(1) 不稳定

近乎有序数据可优先考虑插入排序;要求最坏 O(n log n) 且内存严格受限时可考虑堆排序;平均性能和缓存行为重要时常用快速排序;需要保持相等元素相对顺序时必须选择稳定算法或增加稳定化处理。

相关推荐
2601_967979123 小时前
机器学习必修课:经典算法与Python实战
python·算法·机器学习·实战·课程
程序猿打工仔3 小时前
计算机基础(C语言)考编、专技岗
c语言·开发语言·算法
通信小呆呆3 小时前
电子战干扰技术:从“蛮力压制”到“精准欺骗”,再到“认知博弈”
算法·通信·isac
老师我太想进步了20264 小时前
【数据结构-6】算法美学之单链表(1)
数据结构·算法
希望我万事顺遂5 小时前
力扣hot100-滑动窗口最大值
数据结构·算法·leetcode
꧁细听勿语情꧂5 小时前
二叉树余题,排序、直接插入排序、希尔排序
c语言·开发语言·数据结构·算法
是main不是漫5 小时前
【双指针|LeetCode1089 复写零】巧用逆向思路,破解原地覆盖陷阱
数据结构·算法·leetcode
专注仿真15 小时前
知识问答模型用到的算法集详解及代码实例
python·算法·代码·大模型训练·控制算法
罗西的思考16 小时前
【轻量化复刻大模型 / KIMI K3】AttnRes 模块交互式演示
人工智能·算法·机器学习
好悬给我拽开线20 小时前
ZILOT 论文解析
算法