归并排序

归并排序的思路

归并排序是一种分治算法,通过递归将数组拆分为更小的子数组,再逐步合并已排序的子数组。其核心思想是将两个有序数组合并为一个更大的有序数组。

递归拆分阶段:将数组不断对半分割,直到子数组长度为1(天然有序)。

合并阶段:将两个有序子数组合并为一个有序数组,通过双指针遍历比较元素大小,依次选择较小的元素放入结果数组。

归并排序的C++实现

#include <vector>
using namespace std;

void merge(vector<int>& arr, int left, int mid, int right) {
    vector<int> temp(right - left + 1);
    int i = left, j = mid + 1, k = 0;

    // 比较左右子数组元素,按序放入临时数组
    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 (int p = 0; p < k; p++) {
        arr[left + p] = temp[p];
    }
}

void mergeSort(vector<int>& arr, int left, int right) {
    if (left >= right) return;
    int mid = left + (right - left) / 2;
    mergeSort(arr, left, mid);     // 递归排序左半部分
    mergeSort(arr, mid + 1, right); // 递归排序右半部分
    merge(arr, left, mid, right);   // 合并两部分
}

代码详解

merge函数:负责合并两个有序子数组。通过双指针ij分别遍历左右子数组,比较当前元素大小,将较小的放入临时数组。当某一子数组遍历完成后,将另一子数组剩余元素直接追加到临时数组末尾。最后将临时数组数据拷贝回原数组的对应位置。

mergeSort函数:递归拆分数组直至子数组长度为1。计算中点mid后,分别对左右子数组递归调用mergeSort,最后调用merge合并已排序的子数组。

关键点

  • 时间复杂度: O ( n l o g n ) O(n log n) O(nlogn),递归深度为log n,每层合并操作需 O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n),合并时需要临时数组存储数据。
  • 稳定性:相等元素的相对顺序不变,是稳定排序。

常用实现方法

递归实现归并排序

递归方法是最经典的归并排序实现方式。通过将数组不断分成两半,直到子数组长度为1,然后合并排序后的子数组。

void merge(int arr[], int l, int m, int r) {
    int n1 = m - l + 1;
    int n2 = r - m;
    int L[n1], R[n2];
    for (int i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (int j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];
    int i = 0, j = 0, k = l;
    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++;
    }
}

void mergeSort(int arr[], int l, int r) {
    if (l >= r) return;
    int m = l + (r - l) / 2;
    mergeSort(arr, l, m);
    mergeSort(arr, m + 1, r);
    merge(arr, l, m, r);
}

迭代实现归并排序

迭代方法避免了递归调用的开销,使用循环和变量控制来模拟递归过程。

void merge(int arr[], int l, int m, int r) {
    // 合并逻辑与递归实现相同
}

void mergeSort(int arr[], int n) {
    int curr_size;
    int left_start;
    for (curr_size = 1; curr_size <= n - 1; curr_size = 2 * curr_size) {
        for (left_start = 0; left_start < n - 1; left_start += 2 * curr_size) {
            int mid = min(left_start + curr_size - 1, n - 1);
            int right_end = min(left_start + 2 * curr_size - 1, n - 1);
            merge(arr, left_start, mid, right_end);
        }
    }
}

使用STL实现归并排序

可以利用C++标准库中的std::mergestd::inplace_merge简化实现。

#include <algorithm>
#include <vector>

void mergeSort(std::vector<int>& arr, int l, int r) {
    if (l >= r) return;
    int m = l + (r - l) / 2;
    mergeSort(arr, l, m);
    mergeSort(arr, m + 1, r);
    std::inplace_merge(arr.begin() + l, arr.begin() + m + 1, arr.begin() + r + 1);
}

并行归并排序

对于大型数据集,可以使用多线程加速归并排序过程。注意需要合理处理线程同步和数据分割。

#include <thread>
#include <vector>

void parallelMergeSort(int arr[], int l, int r, int depth = 0) {
    if (l >= r) return;
    int m = l + (r - l) / 2;
    if (depth < std::thread::hardware_concurrency()) {
        std::thread left(parallelMergeSort, arr, l, m, depth + 1);
        parallelMergeSort(arr, m + 1, r, depth + 1);
        left.join();
    } else {
        parallelMergeSort(arr, l, m, depth);
        parallelMergeSort(arr, m + 1, r, depth);
    }
    merge(arr, l, m, r);
}

优化空间使用

传统归并排序需要额外空间,可以通过以下方法优化:

  1. 原地归并排序(较复杂且可能影响时间复杂度)
  2. 交替使用输入数组作为辅助空间
void mergeSortOptimized(int arr[], int n) {
    int* temp = new int[n];
    for (int size = 1; size < n; size *= 2) {
        for (int left = 0; left < n; left += 2 * size) {
            int mid = min(left + size - 1, n - 1);
            int right = min(left + 2 * size - 1, n - 1);
            if (mid < right) {
                merge(arr, temp, left, mid, right);
            }
        }
    }
    delete[] temp;
}
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐