算法笔记之归并排序

本系列可作为算法学习系列的笔记,小编会将代码记录下来,大家复制下来就可以练习了,方便大家学习。小编作为新晋码农一枚,会定期整理一些写的比较好的代码,作为自己的学习笔记,会试着做一下批注和补充,如转载或者参考他人文献会标明出处,非商用,如有侵权会删改!欢迎大家斧正和讨论!

系列文章目录 

计算矩阵的鞍点个数

算法-比较排序

为什么比较排序算法的时间复杂度下界是 Ω(n log n)? 

算法笔记之堆排序 

算法笔记之归并排序


目录

系列文章目录 

​​1. 算法步骤​​

​​2. 示例​​

​​3. 伪代码​​

​​4. 时间复杂度​​

​​5. 稳定性​​

(1)​​稳定排序(Stable Sorting)​​

​​①. 为什么稳定性重要?​​

②. 稳定排序的判定示例​​

③. 常见稳定排序算法​​

④. 不稳定排序算法举例​​

⑤. 如何验证稳定性?​​

⑥. 实际应用场景​​

​​6. 优缺点​​

​​7. 应用场景​​


 归并排序(Merge Sort)是一种基于​​分治法​​(Divide and Conquer)的高效排序算法,其核心思想是将数组递归地分成两半,分别排序后再合并。以下是其详细步骤和特性分析:


​1. 算法步骤​

  1. ​分解(Divide)​

    • 将当前数组从中间分成两个子数组,直到每个子数组只剩一个元素(此时自然有序)。
  2. ​解决(Conquer)​

    • 递归地对左右子数组进行归并排序。
  3. ​合并(Merge)​

    • 将两个已排序的子数组合并为一个有序数组:
      • 创建一个临时数组,依次比较两个子数组的首元素,将较小者放入临时数组。
      • 将剩余未合并的元素直接追加到临时数组末尾。
      • 将临时数组拷贝回原数组的对应位置。

​2. 示例​

​原始数组​​:[38, 27, 43, 3, 9, 82, 10]
​分解过程​​:

[38, 27, 43, 3] 和 [9, 82, 10]  
→ [38, 27], [43, 3], [9, 82], [10]  
→ [38], [27], [43], [3], [9], [82], [10](单元素数组已有序)

​合并过程​​:

  • 合并 [38][27][27, 38]
  • 合并 [43][3][3, 43]
  • 合并 [27, 38][3, 43][3, 27, 38, 43]
  • 同理,右侧合并为 [9, 10, 82]
  • 最终合并为 [3, 9, 10, 27, 38, 43, 82]

​3. 伪代码​

def merge_sort(arr):
    if len(arr) > 1:
        mid = len(arr) // 2
        left = arr[:mid]
        right = arr[mid:]
        
        merge_sort(left)   # 递归排序左半部分
        merge_sort(right)  # 递归排序右半部分
        
        # 合并
        i = j = k = 0
        while i < len(left) and j < len(right):
            if left[i] < right[j]:
                arr[k] = left[i]
                i += 1
            else:
                arr[k] = right[j]
                j += 1
            k += 1
        
        # 处理剩余元素
        while i < len(left):
            arr[k] = left[i]
            i += 1
            k += 1
        while j < len(right):
            arr[k] = right[j]
            j += 1
            k += 1

​4. 时间复杂度​

  • ​最优/最差/平均​​:均为 ​​O(n log n)​

    • 分解:每次将数组分成两半,共 log n 层递归。
    • 合并:每层需 O(n) 时间遍历所有元素。
  • ​空间复杂度​​:O(n)

    • 需要额外临时数组存储合并结果(递归栈空间为 O(log n))。

​5. 稳定性​

归并排序是​​稳定排序​​,因为合并时遇到相等元素会优先保留左子数组的元素(通过 left[i] < right[j] 的条件保证)。

补充:

(1)​​稳定排序(Stable Sorting)​

​稳定排序​​是指排序算法在排序前后,​​相等元素的相对顺序保持不变​​。换句话说,如果两个元素的值相同,排序后它们的先后顺序与排序前的原始顺序一致。

​①. 为什么稳定性重要?​
  • ​多条件排序​​:例如,先按年龄排序,再按姓名排序。如果排序算法是稳定的,相同年龄的人会保持姓名的原始顺序。
  • ​数据完整性​​:某些场景要求保留原始数据的相对顺序(如日志记录、交易记录等)。
②. 稳定排序的判定示例​

​原始数组​​:[ (3, "A"), (2, "B"), (3, "C"), (1, "D") ](每个元素是一个 (数字, 字母) 对)
​按数字排序后​​:

  • ​稳定排序结果​​:[ (1, "D"), (2, "B"), (3, "A"), (3, "C") ]
    • 两个 3 的顺序保持原始顺序("A" 仍在 "C" 前面)。
  • ​不稳定排序结果​​:[ (1, "D"), (2, "B"), (3, "C"), (3, "A") ]
    • 两个 3 的顺序被颠倒("C" 跑到了 "A" 前面)。
③. 常见稳定排序算法​
算法时间复杂度空间复杂度稳定性
归并排序O(n log n)O(n)✔️ 稳定
冒泡排序O(n²)O(1)✔️ 稳定
插入排序O(n²)O(1)✔️ 稳定
计数排序O(n + k)O(n + k)✔️ 稳定
基数排序O(d(n + k))O(n + k)✔️ 稳定
④. 不稳定排序算法举例​
  • ​快速排序​​(Quick Sort):分区过程中可能交换相等元素。
  • ​堆排序​​(Heap Sort):堆的调整会破坏相等元素的顺序。
  • ​选择排序​​(Selection Sort):交换非相邻元素可能导致顺序颠倒。
⑤. 如何验证稳定性?​
  1. 构造一个包含重复键值的数据集(如 [ (2, "X"), (1, "Y"), (2, "Z") ])。
  2. 排序后检查相同键值的元素是否保持原始顺序("X" 是否仍在 "Z" 前面)。
⑥. 实际应用场景​
  • ​数据库排序​​:ORDER BY 多列时需保持稳定性。
  • ​图形渲染​​:按深度排序后,相同深度的物体需保持绘制顺序。
  • ​版本控制​​:按时间戳排序时,相同时间的提交需保留原始提交顺序。

​6. 优缺点​

  • ​优点​​:
    • 时间复杂度稳定为 O(n log n),适合大规模数据。
    • 适用于链表排序(无需随机访问)。
  • ​缺点​​:
    • 需要额外空间,不适合内存受限的场景。
    • 对小规模数据可能不如插入排序高效(可结合其他算法优化)。

​7. 应用场景​

  • 需要稳定排序的场景(如数据库排序)。
  • 外部排序(如大文件处理,因归并排序可分段加载数据)。

归并排序通过分治策略将问题分解为更小的子问题,是理解递归和分治思想的经典案例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值