高级排序算法与性能对比——归并、非比较排序及总结

高级排序算法与性能对比------归并、非比较排序及总结

1. 归并排序

基本思想 :

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,采用分治法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

核心步骤:分解 -> 合并。

代码实现:

c 复制代码
void _MergeSort(int* a, int left, int right, int* tmp) {
    if (left >= right) return;
    int mid = (right + left) / 2;
    // [left, mid] [mid+1, right]
    _MergeSort(a, left, mid, tmp);
    _MergeSort(a, mid + 1, right, tmp);

    int begin1 = left, end1 = mid;
    int begin2 = mid + 1, end2 = right;
    int index = begin1;

    // 合并两个有序数组
    while (begin1 <= end1 && begin2 <= end2) {
        if (a[begin1] < a[begin2]) tmp[index++] = a[begin1++];
        else tmp[index++] = a[begin2++];
    }
    while (begin1 <= end1) tmp[index++] = a[begin1++];
    while (begin2 <= end2) tmp[index++] = a[begin2++];

    for (int i = left; i <= right; i++) a[i] = tmp[i];
}

void MergeSort(int* a, int n) {
    int* tmp = new int[n];
    _MergeSort(a, 0, n - 1, tmp);
    delete[] tmp;
}

特性总结:

  • 时间复杂度:(O(N \log N)),非常稳定。
  • 空间复杂度:(O(N))。
  • 稳定性:稳定。

2. 非比较排序:计数排序

基本思想 :

计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。

  1. 统计相同元素出现次数。
  2. 根据统计的结果将序列回收到原来的序列中。

优化技巧 :如果数据范围较大但集中(如100-109),可以按范围开空间,使用 a[i] - min 作为索引。

代码实现:

c 复制代码
void CountSort(int* a, int n) {
    int min = a[0], max = a[0];
    for (int i = 1; i < n; i++) {
        if (a[i] > max) max = a[i];
        if (a[i] < min) min = a[i];
    }
    int range = max - min + 1;
    int* count = (int*)malloc(sizeof(int) * range);
    memset(count, 0, sizeof(int) * range);

    // 统计次数
    for (int i = 0; i < n; i++) count[a[i] - min]++;

    // 排序
    int j = 0;
    for (int i = 0; i < range; i++) {
        while (count[i]--) a[j++] = i + min;
    }
    free(count);
}

特性总结:

  • 时间复杂度:(O(N + range))。
  • 空间复杂度:(O(range))。
  • 稳定性:稳定。
  • 适用场景:数据范围集中时效率极高,但适用范围有限。

3. 排序算法复杂度及稳定性分析

3.1 稳定性定义

假定在待排序的记录序列中,存在多个具有相同关键字的记录。若经过排序,这些记录的相对次序保持不变,则称这种排序算法是稳定 的;否则称为不稳定。

3.2 综合对比表

排序方法 平均情况 最好情况 最坏情况 辅助空间 稳定性
冒泡排序 (O(n^2)) (O(n)) (O(n^2)) (O(1)) 稳定
直接选择排序 (O(n^2)) (O(n^2)) (O(n^2)) (O(1)) 不稳定
直接插入排序 (O(n^2)) (O(n)) (O(n^2)) (O(1)) 稳定
希尔排序 (O(n \log n) \sim O(n^2)) (O(n^{1.3})) (O(n^2)) (O(1)) 不稳定
堆排序 (O(n \log n)) (O(n \log n)) (O(n \log n)) (O(1)) 不稳定
归并排序 (O(n \log n)) (O(n \log n)) (O(n \log n)) (O(n)) 稳定
快速排序 (O(n \log n)) (O(n \log n)) (O(n^2)) (O(\log n) \sim O(n)) 不稳定

3.3 稳定性验证案例

  • 直接选择排序 :5 8 5 2 9(第一个5会被交换到后面,导致不稳定)。
  • 希尔排序 :5 8 2 5 9(相同元素可能被分到不同组,导致相对位置改变)。
  • 堆排序 :2 2 2 2(建堆和调整过程中可能改变相同元素的相对顺序)。
  • 快速排序 :5 3 3 4 3 8 9 10 11(基准值交换可能导致相同元素顺序改变)。

4. 总结

在实际开发中:

  • 若追求平均性能 ,首选快速排序。
  • 若要求稳定性 ,首选归并排序。
  • 若数据基本有序 ,插入排序效率极高。
  • 若数据范围集中 ,计数排序是最优解。
  • 若考虑空间受限 ,堆排序是很好的选择。
相关推荐
其实防守也摸鱼21 小时前
个人学习 Pwn 思路:从基础到漏洞利用的进阶路径
大数据·前端·人工智能·chrome·算法·安全·网络安全
Nuanyt1 天前
LeetCode Hot 100 链表专题(五)· 2 题(Java)
java·算法·leetcode·链表
w_zero_one1 天前
递归算法(一)
java·开发语言·算法
风影同志783241 天前
20 个比特能装下多少行情?——实测拆解 Kronos 的 K 线分词器
算法
写的都是BUG1 天前
APK 里的钥匙,一直就放在门口:聊聊加固真正该做什么
前端·算法
地平线开发者1 天前
CLIP 的零样本分类:一组文本如何变成图像分类器?
算法
京东云开发者1 天前
从“会生成”到“能生产”:萤火虫 AIGC 平台的 AI Infra 实践
算法·aigc·产品
youshi66681 天前
PID——算法改进
算法
一只不想敲代码的程序猿1 天前
如何更高效地拆解问题?
算法