排序算法--归并排序

归并排序是分治法的经典实现,适合大规模数据排序,尤其适合需要稳定排序的场景(如数据库排序)

cpp 复制代码
#include <stdlib.h> // 用于动态内存分配
// 合并两个已排序的子数组
void merge(int arr[], int left, int mid, int right) {
    int i, j, k;
    int n1 = mid - left + 1; // 左子数组长度
    int n2 = right - mid;    // 右子数组长度

    // 创建临时数组
    int* L = (int*)malloc(n1 * sizeof(int));
    int* R = (int*)malloc(n2 * sizeof(int));

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

    // 合并临时数组到原数组
    i = 0;    // 左数组索引
    j = 0;    // 右数组索引
    k = left; // 合并后的数组索引

    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            i++;
        } else {
            arr[k] = R[j];
            j++;
        }
        k++;
    }

    // 复制剩余元素
    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }
    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }

    free(L); // 释放临时内存
    free(R);
}

// 归并排序递归函数
void mergeSort(int arr[], int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2; // 防止整数溢出
        mergeSort(arr, left, mid);    // 排序左半部分
        mergeSort(arr, mid + 1, right); // 排序右半部分
        merge(arr, left, mid, right);  // 合并结果
    }
}
cpp 复制代码
#include <stdio.h>
// 打印数组函数
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int arr[] = {12, 11, 13, 5, 6, 7}; // 待排序数组
    int n = sizeof(arr) / sizeof(arr[0]); // 计算数组长度

    printf("排序前的数组: \n");
    printArray(arr, n);

    mergeSort(arr, 0, n - 1); // 调用归并排序

    printf("排序后的数组: \n");
    printArray(arr, n);

    return 0;
}

优化建议

  1. **避免重复内存分配:**每次合并时动态分配临时数组会带来性能损耗,可以预先分配一个全局临时数组,减少内存分配次数。

  2. **小数组使用插入排序:**当子数组规模较小时(如长度 ≤ 15),插入排序效率更高,可减少递归调用开销。

  3. **非递归实现(自底向上):**用循环代替递归,避免栈溢出风险,适合超大规模数据。

  4. **提前检查有序性:**合并前检查左右子数组是否已有序,避免不必要的合并操作。

优化后代码:

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

// 插入排序(用于小规模数据)
void insertionSort(int arr[], int left, int right) {
    for (int i = left + 1; i <= right; i++) {
        int key = arr[i];
        int j = i - 1;
        while (j >= left && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

// 合并函数(使用预分配临时数组)
void merge(int arr[], int temp[], int left, int mid, int right) {
    int i = left, j = mid + 1, k = left;
    while (i <= mid && j <= right) {
        if (arr[i] <= arr[j]) {
            temp[k++] = arr[i++];
        } else {
            temp[k++] = arr[j++];
        }
    }
    while (i <= mid) temp[k++] = arr[i++];
    while (j <= right) temp[k++] = arr[j++];
    // 将临时数组复制回原数组
    for (k = left; k <= right; k++) {
        arr[k] = temp[k];
    }
}

// 归并排序主函数(递归+优化)
void mergeSort(int arr[], int temp[], int left, int right) {
    const int INSERTION_THRESHOLD = 15; // 插入排序阈值
    if (right - left <= INSERTION_THRESHOLD) {
        insertionSort(arr, left, right);
        return;
    }
    
    int mid = left + (right - left) / 2;
    mergeSort(arr, temp, left, mid);
    mergeSort(arr, temp, mid + 1, right);
    
    // 检查是否已有序
    if (arr[mid] <= arr[mid + 1]) return;
    
    merge(arr, temp, left, mid, right);
}

// 封装的归并排序入口函数
void optimizedMergeSort(int arr[], int n) {
    int* temp = (int*)malloc(n * sizeof(int)); // 预分配临时数组
    if (temp == NULL) {
        printf("内存分配失败\n");
        return;
    }
    mergeSort(arr, temp, 0, n - 1);
    free(temp);
}

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

int main() {
    int arr[] = {12, 11, 13, 5, 6, 7, 3, 2, 8};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("排序前: ");
    printArray(arr, n);

    optimizedMergeSort(arr, n);

    printf("排序后: ");
    printArray(arr, n);

    return 0;
}

优化说明:

优化点 改进效果 适用场景
预分配临时数组 减少内存分配次数,提升性能 大规模数据排序
小数组插入排序 减少递归深度,降低函数调用开销 子数组长度 ≤ 15
提前检查有序性 避免不必要的合并操作 输入数据部分有序
入口函数封装 简化调用逻辑,隐藏临时数组细节 通用

进一步优化方向:

**1.自底向上非递归实现,**通过循环迭代代替递归,避免栈溢出

cpp 复制代码
void bottomUpMergeSort(int arr[], int n) {
    int* temp = (int*)malloc(n * sizeof(int));
    for (int size = 1; size < n; size *= 2) {
        for (int left = 0; left < n - size; left += 2 * size) {
            int mid = left + size - 1;
            int right = (left + 2 * size - 1 < n - 1) ? left + 2 * size - 1 : n - 1;
            merge(arr, temp, left, mid, right);
        }
    }
    free(temp);
}

**2.原地归并排序:**减少空间复杂度至 O(1)O(1),但实现复杂且时间效率可能降低。

优化后的归并排序在保持稳定性的前提下,显著提升了实际运行效率,尤其适合处理大规模或部分有序的数据集。

相关推荐
fegxg9 分钟前
FastPlanner论文解读(一)——前端路径搜索
c++·机器人·无人机
tt55555555555515 分钟前
每日一题——滑动窗口的最大值
c语言·数据结构·算法·leetcode·八股文
眼镜哥(with glasses)35 分钟前
蓝桥杯python基础算法(2-2)——基础算法(D)——进制转换*
算法
画个逗号给明天"39 分钟前
C++11新特性之long long超长整形
开发语言·c++
和风化雨1 小时前
排序算法--选择排序
c语言·c++·算法·排序算法
和风化雨1 小时前
排序算法--桶排序
c语言·数据结构·c++·算法·排序算法
重生之我在20年代敲代码1 小时前
【C++】STL——vector底层实现
c++
重生之我在20年代敲代码2 小时前
【C++】STL——vector的使用
开发语言·c++
董董灿是个攻城狮2 小时前
DeepSeek-R1 技术报告精华整理:通过强化学习提升大模型推理能力
算法
小姚也要变强2 小时前
sort排序 计数排序 map set C++ 蓝桥杯
开发语言·c++·算法·蓝桥杯