C语言---排序算法5---迭代归并排序法

文章目录

归并排序(Merge Sort)是一种基于分治思想的排序算法,其迭代实现(自底向上)通过逐步合并有序子数组来完成排序,避免了递归调用的开销。

算法原理

1、分阶段:将数组视为由多个长度为1的子数组组成(初始时每个元素自成一个有序子数组)。

2、合阶段:逐步合并相邻的子数组,每次合并后子数组长度翻倍(1→2→4→...),直到整个数组有序。

迭代法步骤

1、初始化:设置子数组的初始长度 size = 1。

2、循环合并:

将数组分成多个长度为 size 的子数组。

合并相邻的两个子数组(每个子数组内部已有序),生成一个长度为 2size 的有序子数组。
如果剩余元素不足 2
size,直接合并剩余部分。

3、更新长度:size *= 2,重复合并直到 size >= n(数组长度)。

代码实现

代码实现1:

bash 复制代码
#include <stdio.h>
#include <stdlib.h>

// 合并两个有序子数组 arr[left..mid] 和 arr[mid+1..right]
void merge(int arr[], int left, int mid, int right) {
    int n1 = mid - left + 1;
    int n2 = right - mid;
    int *L = (int *)malloc(n1 * sizeof(int));
    int *R = (int *)malloc(n2 * sizeof(int));

    // 拷贝数据到临时数组
    for (int i = 0; i < n1; i++) L[i] = arr[left + i];
    for (int j = 0; j < n2; j++) R[j] = arr[mid + 1 + j];

    // 合并临时数组回原数组
    int i = 0, j = 0, k = left;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) arr[k++] = L[i++];
        else arr[k++] = R[j++];
    }
    while (i < n1) arr[k++] = L[i++];
    while (j < n2) arr[k++] = R[j++];

    free(L);
    free(R);
}

// 迭代法归并排序
void mergeSortIterative(int arr[], int n) {
    int size = 1; // 初始子数组长度为1
    while (size < n) {
        int left = 0;
        while (left < n - 1) {
            int mid = left + size - 1;
            if (mid >= n - 1) mid = n - 1; // 防止越界
            int right = (left + 2 * size - 1) < (n - 1) ? (left + 2 * size - 1) : (n - 1);
            merge(arr, left, mid, right);
            left += 2 * size; // 移动到下一对子数组的起始位置
        }
        size *= 2; // 子数组长度翻倍
    }
}

// 测试代码
int main() {
    int arr[] = {12, 11, 13, 5, 6, 7};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("原始数组: ");
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");

    mergeSortIterative(arr, n);

    printf("排序后数组: ");
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");

    return 0;
}

代码实现2(摘抄自菜鸟教程):

c 复制代码
#include <stdio.h>
#include <stdlib.h>
 
// 函数声明
int min(int x, int y);
void merge_sort(int arr[], int len);
 
int main() {
    int arr[] = { 22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70 };
    int len = sizeof(arr) / sizeof(arr[0]);  // 计算数组长度
 
    merge_sort(arr, len);  // 调用归并排序函数
 
    // 打印排序后的数组
    for (int i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
 
    return 0;
}
 
// 返回两个数中的最小值
int min(int x, int y) {
    return x < y ? x : y;
}
 
// 归并排序函数
void merge_sort(int arr[], int len) {
    int* a = arr;
    int* b = (int*) malloc(len * sizeof(int));
 
    if (b == NULL) {  // 检查内存分配是否成功
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }
 
    for (int seg = 1; seg < len; seg += seg) {
        for (int start = 0; start < len; start += seg + seg) {
            int low = start;
            int mid = min(start + seg, len);
            int high = min(start + seg + seg, len);
            int k = low;
            int start1 = low, end1 = mid;
            int start2 = mid, end2 = high;
 
            // 合并两个子数组
            while (start1 < end1 && start2 < end2) {
                b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
            }
            while (start1 < end1) {
                b[k++] = a[start1++];
            }
            while (start2 < end2) {
                b[k++] = a[start2++];
            }
        }
 
        // 交换数组指针
        int* temp = a;
        a = b;
        b = temp;
    }
 
    // 如果a和arr不相同,则将a的内容复制回arr
    if (a != arr) {
        for (int i = 0; i < len; i++) {
            b[i] = a[i];
        }
        b = a;
    }
 
    free(b);  // 释放内存
}

迭代法 vs 递归法

特性 迭代法 递归法
实现方式 通过循环逐步合并子数组 通过递归分解问题
空间开销 仅需临时数组空间 递归栈空间(可能栈溢出)
代码复杂度 稍复杂(需手动管理边界) 更简洁(分治逻辑直观)

优化方向

1、小数组优化:当子数组长度较小时(如 size <= 16),改用插入排序以减少常数因子。

2、原地归并:通过复杂指针操作减少临时空间使用(但实现难度高,可能牺牲稳定性)。

学习视频推荐

数据结构合集 - 归并排序(非递归与递归算法过程, 效率分析, 稳定性分析)

相关推荐
爱理财的程序媛4 小时前
openclaw 盯盘实践
算法
MobotStone8 小时前
Google发布Nano Banana 2:更快更便宜,图片生成能力全面升级
算法
颜酱11 小时前
队列练习系列:从基础到进阶的完整实现
javascript·后端·算法
用户57573033462411 小时前
两数之和:从 JSON 对象到 Map,大厂面试官到底在考察什么?
算法
程序猿追11 小时前
“马”上行动:手把手教你基于灵珠平台打造春节“全能数字管家”
算法
norlan_jame1 天前
C-PHY与D-PHY差异
c语言·开发语言
ZPC82101 天前
docker 镜像备份
人工智能·算法·fpga开发·机器人
ZPC82101 天前
docker 使用GUI ROS2
人工智能·算法·fpga开发·机器人
琢磨先生David1 天前
Day1:基础入门·两数之和(LeetCode 1)
数据结构·算法·leetcode