You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

归并排序:递归与非递归实现孰优?递归是否不利于编译器?

嘿,很高兴你深入研究了归并排序的两种实现方式,咱们来拆解你的问题和看法~

先看你提到的两种实现代码

递归式归并排序

#include <stdio.h>
#define MAX 30  // 补充原代码缺失的宏定义以保证编译正常
void merge(int array[], int low, int mid, int high) {
    int temp[MAX];
    int i = low;
    int j = mid + 1;
    int k = low;
    while ((i <= mid) && (j <= high)) {
        if (array[i] <= array[j])
            temp[k++] = array[i++];
        else
            temp[k++] = array[j++];
    }/*End of while*/
    while (i <= mid)
        temp[k++] = array[i++];
    while (j <= high)
        temp[k++] = array[j++];
    for (i = low; i <= high; i++)
        array[i] = temp[i];
}/*End of merge()*/
void merge_sort(int array[], int low, int high) {
    int mid;
    if (low != high) {
        mid = (low + high) / 2;
        merge_sort(array, low, mid);
        merge_sort(array, mid + 1, high);
        merge(array, low, mid, high);
    }
}/*End of merge_sort*/

非递归式归并排序

#include <stdio.h>
#define MAX 30
int main() {
    int arr[MAX], temp[MAX], i, j, k, n, size, l1, h1, l2, h2;
    printf("Enter the number of elements : ");
    scanf("%d", &n);
    for (i = 0; i < n; i++) {
        printf("Enter element %d : ", i + 1);
        scanf("%d", &arr[i]);
    }
    printf("Unsorted list is : ");
    for (i = 0; i < n; i++)
        printf("%d ", arr[i]);
    /* l1 lower bound of first pair and so on */
    for (size = 1; size < n; size = size * 2) {
        l1 = 0;
        k = 0; /* Index for temp array */
        while (l1 + size < n) {
            h1 = l1 + size - 1;
            l2 = h1 + 1;
            h2 = l2 + size - 1;
            /* h2 exceeds the limlt of arr */
            if (h2 >= n)
                h2 = n - 1;
            /* Merge the two pairs with lower limits l1 and l2 */
            i = l1;
            j = l2;
            while (i <= h1 && j <= h2) {
                if (arr[i] <= arr[j])
                    temp[k++] = arr[i++];
                else
                    temp[k++] = arr[j++];
            }
            while (i <= h1)
                temp[k++] = arr[i++];
            while (j <= h2)
                temp[k++] = arr[j++];
            /** Merging completed **/
            /*Take the next two pairs for merging */
            l1 = h2 + 1;
        }/*End of while*/
        /*any pair left */
        for (i = l1; k < n; i++)
            temp[k++] = arr[i];
        for (i = 0; i < n; i++)
            arr[i] = temp[i];
        printf("\nSize=%d \nElements are : ", size);
        for (i = 0; i < n; i++)
            printf("%d ", arr[i]);
    }/*End of for loop */
    printf("Sorted list is :\n");
    for (i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
    return 0;
}/*End of main()*/

关于“递归实现对编译器不友好”的看法

你的观点有一定合理性,但也不用把递归一棒子打死:

  • 递归归并排序的递归深度是log₂(n),比如处理100万元素的数组,递归深度大概只有20层——大多数系统的默认栈空间(几MB)完全能容纳这么小的栈帧,所以普通场景下根本不会出现栈溢出问题。只有处理极端巨大的数组(比如10亿级)时,递归深度才可能达到30层左右,这时候才需要担心栈溢出。
  • 编译器对递归的优化确实有限:归并排序的递归不是尾递归(尾递归是指递归调用是函数的最后一个操作,编译器可以把它优化成循环),所以编译器没办法自动把它转换成循环结构,每一层递归都会创建新的栈帧,确实会有一些额外的开销,但这个开销在普通场景下几乎可以忽略。

递归 vs 非递归:哪种实现更好?

这完全取决于你的使用场景:

优先选递归的场景

  • 代码可读性和可维护性:递归代码完全贴合归并排序的分治思想,逻辑清晰到一眼就能看懂,调试和维护起来比非递归简单太多。
  • 常规数据规模:如果处理的是百万级以内的数组,递归的栈开销可以忽略,而且递归拆分的子数组更容易被CPU缓存命中,性能甚至不比非递归差。

优先选非递归的场景

  • 超大数组或受限环境:比如处理十亿级别的数据,或者在嵌入式系统这种栈空间极小的环境下,非递归实现完全不依赖程序栈,能避免栈溢出风险。
  • 极致性能优化:如果你的场景对性能要求到了极致,非递归可以省去栈帧创建销毁的开销,虽然差异很小,但确实存在。

总结

递归归并非不是“不好的编程方式”,它只是在特定场景下有局限。在大多数日常开发中,递归实现是更优的选择——毕竟代码简洁、易读,出错概率更低。只有当你遇到超大数组或受限环境时,再考虑非递归实现才更合理。

内容的提问来源于stack exchange,提问作者JINU_K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:25:53