4-5 比较排序:归并排序

归并排序

归并排序是一种流行的排序算法,以其高效性和稳定性而闻名。它遵循分治法。其工作原理是递归地将输入数组分成两半,递归地对这两半进行排序,最后将它们合并在一起,从而得到排序后的数组。

image

以下是归并排序工作原理的详细步骤说明:

  • 分割:递归地将列表或数组分割成两半,直到无法再分割为止。
  • 征服:使用归并排序算法对每个子数组进行单独排序。
  • 合并:将已排序的子数组按排序顺序重新合并。此过程持续进行,直到两个子数组中的所有元素都合并完毕。

代码实现

#include <iostream>
#include <vector>

// Merges two subarrays of arr[].
// First subarray is arr[left..mid]
// Second subarray is arr[mid+1..right]
void merge(std::vector<int>& arr, int left, int mid, int right)
{
    int n1 = mid - left + 1;
    int n2 = right - mid;

    // Create temp vectors
    std::vector<int> L(n1), R(n2);

    // Copy data to temp vectors L[] and R[]
    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;
    int k = left;

    // Merge the temp vectors back
    // into arr[left..right]
    while (i < n1 && j < n2)
    {
        if (L[i] <= R[j])
        {
            arr[k] = L[i];
            i++;
        }
        else
        {
            arr[k] = R[j];
            j++;
        }
        k++;
    }

    // Copy the remaining elements of L[],
    // if there are any
    while (i < n1)
    {
        arr[k] = L[i];
        i++;
        k++;
    }

    // Copy the remaining elements of R[],
    // if there are any
    while (j < n2)
    {
        arr[k] = R[j];
        j++;
        k++;
    }
}

// begin is for left index and end is right index
// of the sub-array of arr to be sorted
void mergeSort(std::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);
}

// Driver code
int main()
{
    std::vector<int> arr = {38, 27, 43, 10};
    int n = arr.size();

    mergeSort(arr, 0, n - 1);
    for (int i = 0; i < arr.size(); i++)
    {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出:

image


归并排序的递推关系、复杂度分析、优缺点、以及应用

归并排序的递推关系为:

        { Θ(1)           , if n = 1
T(n) =  {
        { 2T(n/2) + Θ(n) , if n > 1
  • T(n) 表示算法对大小为 n 的数组进行排序所需的总时间。
  • 2T(n/2) 表示算法递归排序数组两部分所需的时间。由于每部分都有 n/2 个元素,因此需要两次递归调用,每次调用的输入大小为 (n/2)。
  • O(n) 表示合并两个已排序部分所需的时间。

归并排序的复杂度分析
时间复杂度:

  • 最佳情况: O(n log n),当数组已经排序或接近排序时。
  • 平均情况: O(n log n),当数组随机排序时。
  • 最坏情况: O(n log n),当数组按逆序排序时。

辅助空间: O(n),合并过程中使用的临时数组需要额外的空间。


归并排序的优点

  • 稳定性:归并排序是一种稳定的排序算法,这意味着它可以保持输入数组中相等元素的相对顺序。
  • 保证最坏情况下的性能:归并排序的最坏情况时间复杂度为O(N logN),这意味着即使在大型数据集上也能表现良好。
  • 易于实施:分而治之的方法简单明了。
  • 自然并行:我们独立合并子数组,使其适合并行处理。

归并排序的缺点

  • 空间复杂度:归并排序需要在排序过程中使用额外的内存来存储合并后的子数组。
  • 非原地排序:归并排序不是一种原地排序算法,这意味着它需要额外的内存来存储排序后的数据。这在内存使用受限的应用中可能是一个缺点。
  • 一般来说,归并排序比快速排序慢,因为快速排序对缓存更友好,因为它直接在内存中运行。

归并排序的应用:

  • 对大型数据集进行排序
  • 外部排序(当数据集太大而无法放入内存时)
  • 用于解决诸如倒数计数、右侧较小计数和超过计数等问题
  • 归并排序及其变体被广泛应用于编程语言的库方法中。其变体TimSort则被 Python、Java、Android 和 Swift 所采用。归并排序之所以更受青睐,用于对非原始类型进行排序,主要原因在于其稳定性,而快速排序则不具备这种稳定性。Java 中的 Arrays.sort 方法使用快速排序,而Collections.sort 方法则使用归并排序。
  • 它是链表排序的首选算法。
  • 由于我们可以独立地对子数组进行排序,然后再合并,因此很容易实现并行化。
  • 归并排序的 merge 函数可以高效地解决两个已排序数组的并集和交集等问题。
posted @ 2026-03-30 17:45  游翔  阅读(0)  评论(0)    收藏  举报