当前位置: 首页 > news >正文

算法笔记之归并排序

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

系列文章目录 

计算矩阵的鞍点个数

算法-比较排序

为什么比较排序算法的时间复杂度下界是 Ω(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) // 2left = arr[:mid]right = arr[mid:]merge_sort(left)   # 递归排序左半部分merge_sort(right)  # 递归排序右半部分# 合并i = j = k = 0while i < len(left) and j < len(right):if left[i] < right[j]:arr[k] = left[i]i += 1else:arr[k] = right[j]j += 1k += 1# 处理剩余元素while i < len(left):arr[k] = left[i]i += 1k += 1while j < len(right):arr[k] = right[j]j += 1k += 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. 应用场景​

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

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

http://www.dtcms.com/a/293810.html

相关文章:

  • 分享鸢尾花数据集:iris.csv,以及简单数据分析与分类预测示例(决策树)
  • Deep learning--模型压缩的五种方法
  • 沪银本周想法
  • Spring DeferredResult 实现长轮询
  • Http证书体系及证书加密流程(通信流程)
  • 第九章 W55MH32 HTTP Server示例
  • ARM入门学习方法分享
  • 2025年华为HCIA人工智能认证发展前景如何?客观分析!
  • 7月23日华为机考真题第一题100分
  • LazyVim 加载顺序
  • react18更新哪些东西
  • 5G时代PCB设计新突破:猎板三大创新技术重塑高频信号完整性
  • ES6 标签模板:前端框架的灵活利器
  • 2025年电赛--电源题赛前押题
  • LeetCode 460:LFU 缓存
  • LeetCode热题100--383
  • 时序数据库主流产品概览
  • 基于单片机排队叫号系统设计
  • 自动化运维:从脚本到DevOps的演进
  • Win10_Qt6_C++_YOLO推理 -(1)MingW-opencv编译
  • 人工智能——Opencv图像色彩空间转换、灰度实验、图像二值化处理、仿射变化
  • 腾讯iOA:企业软件合规与安全的免费守护者
  • 建数仓该选大SQL还是可视化ETL平台?
  • kotlin基础【2】
  • kettle 8.2 ETL项目【一、初始化数据库及介绍】
  • UniappDay01
  • Django学习之旅--第13课:Django模型关系进阶与查询优化实战
  • 傅里叶转换(机器视觉方向)
  • Oracle19c HINT不生效?
  • Unreal5从入门到精通之使用 Python 编写虚幻编辑器脚本