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

算法笔记之归并排序

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

系列文章目录 

计算矩阵的鞍点个数

算法-比较排序

为什么比较排序算法的时间复杂度下界是 Ω(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.xdnf.cn/news/16096.html

相关文章:

  • Windows 用 Python3 快速搭建 HTTP 服务器
  • linux驱动开发笔记--GPIO驱动开发
  • WPF的一些基础知识学习记录
  • 应用层自定义协议【序列化+反序列化】
  • TODAY()-WEEKDAY(TODAY(),2)+1
  • 彻底掌握双列集合——Map接口以及实现类和常用API及其底层原理
  • python学智能算法(二十九)|SVM-拉格朗日函数求解中-KKT条件
  • Python爬虫--Xpath的应用
  • 分布式限流算法与组件
  • jenkins 入门指南:从安装到启动的完整教程
  • 分布式系统中的缓存设计与应用
  • 网络调制技术对比表
  • 算法竞赛备赛——【图论】拓扑排序
  • 关于网络安全等级保护的那些事
  • 重磅发布:Oracle ADG 一键自动化搭建脚本
  • java设计模式 -【策略模式】
  • 为什么本地ip记录成0.0.0.1
  • 扫地机产品--同理心地图的方法,展现一个功能的痛点提炼
  • 智能营销革命:AI如何重塑个性化广告的创作逻辑
  • 汽车电子架构
  • LeetCode热题100--24. 两两交换链表中的节点--中等
  • 视频孪生赋能数字住建:构建智慧城市新蓝图​
  • TDengine 的 HISTOGRAM() 函数用户手册
  • 如何在 npm 上发布 Element Plus 二次封装组件
  • 算法竞赛备赛——【图论】最小生成树
  • 关于针对 DT_REG 出现红色波浪线的问题(编译错误/IDE警告),以下是 精准解决方案,保持你的代码功能完全不变:
  • 基于数据挖掘的短视频点赞影响因素分析【LightGBM、XGBoost、随机森林、smote】
  • 如何在macOS上修改iPhone的定位
  • uniapp拦截返回事件
  • Android Multidex 完全解析:解决64K方法数限制