跳转到内容

归并排序(Merge Sort)

来自代码酷

归并排序(Merge Sort)[编辑 | 编辑源代码]

归并排序是一种基于分治法(Divide and Conquer)的高效排序算法,由约翰·冯·诺伊曼于1945年提出。它的核心思想是将一个大的问题分解为若干个小问题,递归解决这些小问题,然后将它们的解合并起来得到最终结果。归并排序的时间复杂度为O(nlogn),在大多数情况下表现稳定,适用于大规模数据排序。

算法原理[编辑 | 编辑源代码]

归并排序的主要步骤如下: 1. 分解:将待排序的数组递归地分成两半,直到每个子数组只包含一个元素(此时可视为已排序)。 2. 合并:将两个已排序的子数组合并为一个有序数组,直到所有子数组合并完成。

分治法[编辑 | 编辑源代码]

归并排序采用分治法,其递归关系可以表示为: T(n)=2T(n2)+O(n) 其中:

  • T(n)表示对长度为n的数组排序所需的时间。
  • 2T(n/2)表示递归地对两个子数组排序。
  • O(n)表示合并两个子数组的时间。

算法实现[编辑 | 编辑源代码]

以下是归并排序的伪代码和具体实现(以Python为例)。

伪代码[编辑 | 编辑源代码]

function merge_sort(array):
    if length(array) <= 1:
        return array
    mid = length(array) // 2
    left = merge_sort(array[0..mid])
    right = merge_sort(array[mid..end])
    return merge(left, right)

function merge(left, right):
    result = []
    while left is not empty and right is not empty:
        if left[0] <= right[0]:
            append left[0] to result
            remove left[0] from left
        else:
            append right[0] to result
            remove right[0] from right
    append remaining elements of left to result
    append remaining elements of right to result
    return result

Python实现[编辑 | 编辑源代码]

def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    
    return merge(left, right)

def merge(left, right):
    result = []
    i = j = 0
    
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    
    result.extend(left[i:])
    result.extend(right[j:])
    return result

# 示例输入与输出
arr = [38, 27, 43, 3, 9, 82, 10]
sorted_arr = merge_sort(arr)
print("排序前:", arr)
print("排序后:", sorted_arr)

输出:

排序前: [38, 27, 43, 3, 9, 82, 10]
排序后: [3, 9, 10, 27, 38, 43, 82]

合并过程示例[编辑 | 编辑源代码]

以下是一个合并过程的示例(以数组[38, 27, 43, 3]为例): 1. 分解为[38, 27][43, 3]。 2. 继续分解为[38][27][43][3](均为已排序)。 3. 合并[38][27]得到[27, 38]。 4. 合并[43][3]得到[3, 43]。 5. 最后合并[27, 38][3, 43]得到[3, 27, 38, 43]

时间复杂度分析[编辑 | 编辑源代码]

归并排序的时间复杂度为O(nlogn),具体分析如下:

  • 分解阶段:每次将数组分成两半,共需logn层递归。
  • 合并阶段:每层合并的总时间为O(n)(因为需要遍历所有元素)。
  • 总时间复杂度为O(nlogn)

空间复杂度为O(n),因为合并时需要额外的存储空间。

稳定性[编辑 | 编辑源代码]

归并排序是稳定排序,因为在合并时,如果两个元素相等,优先选择左子数组的元素,不会改变它们的相对顺序。

实际应用[编辑 | 编辑源代码]

归并排序在以下场景中广泛应用: 1. 外部排序:当数据量太大无法全部加载到内存时,归并排序适用于分块排序后合并。 2. 数据库系统:某些数据库的排序操作采用归并排序或其变种。 3. 链表排序:归并排序是链表排序的高效选择,因为链表的合并操作无需额外空间。

示例:外部排序[编辑 | 编辑源代码]

假设有一个100GB的文件需要排序,但内存只有4GB: 1. 将文件分成25个4GB的块,分别加载到内存中排序。 2. 使用归并排序的方法,逐步合并这些已排序的块,最终得到完整的有序文件。

优化与变种[编辑 | 编辑源代码]

1. 自底向上归并排序:避免递归,直接从单个元素开始合并。 2. 原地归并排序:减少空间复杂度(但实现复杂)。 3. TimSort:Python和Java的内置排序算法,结合了归并排序和插入排序的优点。

总结[编辑 | 编辑源代码]

归并排序是一种高效、稳定的排序算法,适用于大规模数据排序。虽然需要额外的存储空间,但其O(nlogn)的时间复杂度使其成为许多实际应用的首选。理解其分治思想和合并过程对掌握算法设计至关重要。

练习[编辑 | 编辑源代码]

尝试实现以下任务: 1. 用你熟悉的编程语言实现归并排序。 2. 修改代码,使其支持降序排序。 3. 分析归并排序在处理近乎有序数组时的性能。

graph TD A[38, 27, 43, 3, 9, 82, 10] --> B[38, 27, 43, 3] A --> C[9, 82, 10] B --> D[38, 27] B --> E[43, 3] D --> F[38] D --> G[27] E --> H[43] E --> I[3] C --> J[9, 82] C --> K[10] J --> L[9] J --> M[82] K --> N[10] F & G --> O[27, 38] H & I --> P[3, 43] L & M --> Q[9, 82] N --> R[10] O & P --> S[3, 27, 38, 43] Q & R --> T[9, 10, 82] S & T --> U[3, 9, 10, 27, 38, 43, 82]