算法-归并排序

归并排序 (Merge Sort)

像"分家再合并"一样,先把队伍从中间劈成两半,一直劈到每个人自成一个小队(天然有序)。然后两两合并,在合并时像"双指针"一样,每次只比较两个小队排头的人,谁小谁先站到新的队伍里。不断向上合并,最后整个队伍就排好序了。

核心代码

c 复制代码
#include <stdio.h>

// 辅助数组,用于在合并时暂存数据
int temp[100]; 

// 合并函数:将两个已排序的子数组合并成一个有序数组
void merge(int arr[], int left, int mid, int right) {
    int i = left;      // 左半部分起始指针
    int j = mid + 1;   // 右半部分起始指针
    int k = left;      // 辅助数组的填充指针
    
    // 双指针比较:哪边小,就把哪边的元素放入 temp
    while (i <= mid && j <= right) {
        if (arr[i] <= arr[j]) {
            temp[k++] = arr[i++];
        } else {
            temp[k++] = arr[j++];
        }
    }
    
    // 将左半部分剩余的元素直接倒入 temp
    while (i <= mid) temp[k++] = arr[i++];
    // 将右半部分剩余的元素直接倒入 temp
    while (j <= right) temp[k++] = arr[j++];
    
    // 将排好序的 temp 数据倒回原数组 arr
    for (int p = left; p <= right; p++) {
        arr[p] = temp[p];
    }
}

// 归并排序函数
void mergeSort(int arr[], int left, int right) {
    if (left >= right) return; // 递归终止条件:区间只有一个元素
    
    int mid = (left + right) / 2; // 找到中间分界点
    mergeSort(arr, left, mid);    // 递归排序左半边
    mergeSort(arr, mid + 1, right); // 递归排序右半边
    merge(arr, left, mid, right); // 合并左右两边
}

// 打印数组的辅助函数
void printArray(int arr[], int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int arr[] = {64, 34, 25, 12, 22};
    int n = sizeof(arr) / sizeof(arr[0]); // 计算数组长度
    
    printf("排序前:");
    printArray(arr, n);
    
    mergeSort(arr, 0, n - 1); // 调用归并排序
    
    printf("排序后:");
    printArray(arr, n);
    return 0;
}

示例演示

{64, 34, 25, 12, 22}

第 1 步:不断递归拆分(分治的"分")

目标:将数组从中间劈开,直到每个子数组只剩 1 个元素。

拆分 {64, 34, 25, 12, 22} -> {64, 34} 和 {25, 12, 22}

继续拆分 {64, 34} -> {64} 和 {34}

继续拆分 {25, 12, 22} -> {25} 和 {12, 22}

继续拆分 {12, 22} -> {12} 和 {22}

拆分结束:得到 5 个单元素子数组,它们天然有序。
第 2 步:自底向上合并(分治的"治")

目标:利用双指针,将相邻的有序子数组合并成更大的有序数组。

合并 {64} 和 {34}:比较 64 > 34,先放 34,再放 64。结果:{34, 64}

合并 {12} 和 {22}:比较 12 < 22,先放 12,再放 22。结果:{12, 22}

合并 {25} 和 {12, 22}:比较 25 > 12,放 12;比较 25 > 22,放 22;左半部分剩 25 直接放入。结果:{12, 22, 25}

当前状态:数组变成了两个有序块:34, 6412, 22, 25
第 3 步:最终合并

目标:将最后两个有序块合并成完整的有序数组。

合并 {34, 64} 和 {12, 22, 25}:

比较 34 > 12,放 12;比较 34 > 22,放 22;比较 34 > 25,放 25。

此时右半边已合并完,将左半边剩余的 {34, 64} 直接追加到末尾。

合并完成。

最终结果:12, 22, 25, 34, 64

复杂度

时间复杂度是 \(O(nlogn)\)(无论最好、最坏还是平均情况,拆分和合并的代价都非常稳定)

空间复杂度是 \(O(n)\)(因为合并时需要借助一个与原数组等长的辅助数组 temp 来暂存数据)

相关推荐
格林威15 分钟前
多相机微秒级对齐:硬件触发 vs PTP(IEEE 1588)方案实战对比
开发语言·人工智能·数码相机·机器学习·计算机视觉·视觉检测·机器视觉
都叫我大帅哥34 分钟前
给 Java 程序员的 CSRF 攻击详解:从原理到防御实战
java
江南十四行43 分钟前
Spring框架核心(上)——IoC控制反转与DI依赖注入详解
java·后端·spring
fb_123452 小时前
Linux磁盘分区从入门到实操:MBR_GPT全解析+分区工具实战指南
java·linux·gpt
初级代码游戏2 小时前
iOS开发 Swift 速记2:三种集合类型 Array Set Dictionary
开发语言·ios·swift
码智社3 小时前
JSON 零基础到资深全体系教程
java·json
AndrewHZ3 小时前
【LLM技术全景】阶段总结:技术原理篇核心知识回顾
人工智能·深度学习·算法·语言模型·大模型·llm·芯片开发
峥嵘life3 小时前
Android WiFi 热点 Channel 信道 和 Frequency 频率 转换总结
android·开发语言
小星星闪亮登场3 小时前
2026萌新联赛第三场-- (郑州轻工业大学)
数据结构·c++·经验分享·算法·贪心算法·排序算法·深度优先
wgego4 小时前
基础的反序列化一些总结(php和java)
java·开发语言·笔记