news 2026/9/21 12:37:18

归并排序的趟数和时间复杂度

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
归并排序的趟数和时间复杂度

一、归并排序的趟数

归并排序的核心是分治思想:先把数组递归地分成两半(分),直到每个子数组只有 1 个元素;再把相邻的子数组合并成有序数组(治)。这里的 “趟数”,本质是合并阶段的轮次(也等于拆分阶段的递归深度)。

1. 趟数的计算逻辑

假设待排序数组的元素个数为n

  • 拆分阶段:每次将数组分成 2 份,直到子数组长度为 1。这个过程的次数等于以 2 为底的 n 的对数(向上取整或向下取整,最终结果一致),数学表示为⌊log₂n⌋⌈log₂n⌉(也可简化为log₂n,因为时间复杂度中对数的底数不影响阶数)。
  • 合并阶段:每一轮合并都是将当前的子数组两两合并,轮次和拆分的次数完全相同,这就是归并排序的趟数
2. 举例说明
  • 例 1:n=8(2³)拆分过程:8 → 4+4 → 2+2+2+2 → 1+1+…+1(共 8 个 1)。拆分次数(趟数):log₂8=3趟。
  • 例 2:n=7(非 2 的幂)拆分过程:7 → 3+4 → 1+2+2+2 → 1+1+1+1+1+1+1。拆分次数(趟数):log₂7≈2.8,向上取整为3 趟(或向下取整⌊log₂7⌋=2,但实际合并时仍需 3 趟,因此通常统一表述为log₂n趟,忽略小数部分的影响)。

结论:归并排序的趟数为 **log2​n**(n为元素个数,对数的底数为 2)。

二、归并排序的时间复杂度

归并排序的时间复杂度需要从拆分阶段合并阶段分别分析,最终结合得出整体复杂度。

1. 拆分阶段的时间复杂度

拆分操作只是将数组分成两半,没有元素的比较和交换,仅涉及索引的计算,时间复杂度为O(1)(每一次拆分),整个拆分阶段的总时间复杂度为 O (log n)(因为拆分次数是 log n 趟),相对于合并阶段可以忽略。

2. 合并阶段的时间复杂度

合并阶段是归并排序的核心,每一趟合并都需要遍历所有 n 个元素(将两两子数组合并时,每个元素都会被处理一次)。

  • 每一趟合并的时间复杂度:O (n)。
  • 总趟数:log n。
  • 因此,合并阶段的总时间复杂度:O (n × log n)。
3. 不同情况下的时间复杂度

归并排序是稳定的排序算法(相同值的元素相对位置不变),且其时间复杂度不受原始数组有序性的影响:

  • 最好情况:O (n log n)(原始数组已有序)。
  • 最坏情况:O (n log n)(原始数组逆序)。
  • 平均情况:O (n log n)。
补充:空间复杂度

归并排序需要额外的辅助数组来存储合并后的元素,因此空间复杂度为O(n)(这是归并排序的主要缺点,相比快速排序的 O (log n) 空间复杂度更高)。

三、代码示例(验证趟数和复杂度)

下面是 Python 实现的归并排序,添加了趟数统计的功能,帮助你直观看到趟数:

python

运行

def merge_sort(arr): # 统计趟数(使用非局部变量,避免全局变量) global merge_pass # 递归终止条件:子数组长度为1 if len(arr) <= 1: return arr # 拆分:将数组分成左右两半 mid = len(arr) // 2 left = merge_sort(arr[:mid]) right = merge_sort(arr[mid:]) # 合并:将两个有序子数组合并 merge_pass += 1 # 每合并一次,趟数+1(这里统计的是合并操作的次数,总趟数为log2n) 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 # 测试 if __name__ == "__main__": # 初始化趟数 merge_pass = 0 arr = [3, 1, 4, 1, 5, 9, 2, 6] sorted_arr = merge_sort(arr) print("排序后的数组:", sorted_arr) print("合并操作的次数(趟数相关):", merge_pass) # 对于n=8,输出7(合并次数),趟数为3(log28=3)

说明:代码中merge_pass统计的是合并操作的次数(比如 n=8 时,合并次数是 7),而我们说的 “趟数” 是合并的轮次(n=8 时是 3 轮),两者的关系是:第 k 趟的合并次数为n/2k,总合并次数为n−1(比如 8-1=7)。

总结

  1. 趟数:归并排序的趟数为 **log2​n**(n 为元素个数,即拆分 / 合并的轮次),若 n 不是 2 的幂,趟数为向上取整后的log2​n。
  2. 时间复杂度:最好、最坏、平均情况均为O(n log n),这是归并排序的核心优势(不受原始数组有序性影响)。
  3. 补充:归并排序的空间复杂度为O(n),因为需要辅助数组存储合并后的元素。

合并阶段是归并排序的核心,每一趟合并都需要遍历所有 n 个元素 讲讲

要理解 “归并排序的每一趟合并都需要遍历所有 n 个元素”,我们需要先明确 “” 的定义(合并阶段的 “轮次”),再结合具体例子拆解每一趟的合并过程 —— 核心逻辑是:每一趟合并的目标是将当前所有 “有序子数组” 两两合并,而这些子数组的总长度恰好是 n,因此遍历的总元素数必然是 n

第一步:先明确 “合并阶段的趟” 是什么

归并排序的 “合并阶段”,是从 “最小有序子数组”(长度为 1 的子数组,天然有序)开始,每一轮(一趟)都将所有相邻的 “同长度有序子数组” 两两合并成 “长度翻倍的有序子数组”,直到最终合并成一个长度为 n 的有序数组。

这里的 “趟”=“合并轮次”,每一趟的核心特征是:

  • 趟内所有待合并的子数组长度相同(记为len);
  • 合并后生成的子数组长度为2*len
  • 每一趟处理的子数组总数是 “当前子数组个数”,但它们的总长度始终是 n。

第二步:用具体例子拆解 “每趟遍历 n 个元素”

n=8(元素:[3,1,4,1,5,9,2,6])为例,合并阶段共 3 趟(因为log₂8=3),我们逐趟分析:

第 1 趟合并:子数组长度 = 1 → 合并后长度 = 2
  • 初始状态:拆分阶段结束后,得到 8 个长度为 1 的有序子数组(每个子数组只有 1 个元素,天然有序):[3], [1], [4], [1], [5], [9], [2], [6]
  • 合并逻辑:将相邻的两个子数组两两合并,共需要合并 4 次(8 个→4 个):
    1. 合并[3][1][1,3](遍历 2 个元素);
    2. 合并[4][1][1,4](遍历 2 个元素);
    3. 合并[5][9][5,9](遍历 2 个元素);
    4. 合并[2][6][2,6](遍历 2 个元素);
  • 第 1 趟总遍历元素数:2+2+2+2 = 8 = n;
  • 第 1 趟结束后:得到 4 个长度为 2 的有序子数组:[1,3], [1,4], [5,9], [2,6]
第 2 趟合并:子数组长度 = 2 → 合并后长度 = 4
  • 当前状态:4 个长度为 2 的有序子数组,总长度仍为 8;
  • 合并逻辑:继续相邻两两合并,共需要合并 2 次(4 个→2 个):
    1. 合并[1,3][1,4]
      • 双指针遍历两个子数组,依次取较小元素:1(来自第二个子数组)→1(第一个)→3(第一个)→4(第二个),最终得到[1,1,3,4](遍历 4 个元素);
    2. 合并[5,9][2,6]
      • 双指针遍历:2(第二个)→5(第一个)→6(第二个)→9(第一个),最终得到[2,5,6,9](遍历 4 个元素);
  • 第 2 趟总遍历元素数:4+4 = 8 = n;
  • 第 2 趟结束后:得到 2 个长度为 4 的有序子数组:[1,1,3,4], [2,5,6,9]
第 3 趟合并:子数组长度 = 4 → 合并后长度 = 8(最终数组)
  • 当前状态:2 个长度为 4 的有序子数组,总长度还是 8;
  • 合并逻辑:最后一次两两合并(2 个→1 个):合并[1,1,3,4][2,5,6,9]
    • 双指针遍历:1(第一个)→1(第一个)→2(第二个)→3(第一个)→4(第一个)→5(第二个)→6(第二个)→9(第二个),最终得到[1,1,2,3,4,5,6,9](遍历 8 个元素);
  • 第 3 趟总遍历元素数:8 = n;
  • 第 3 趟结束后:得到 1 个长度为 n 的有序数组,排序完成。

第三步:为什么 “每趟都必须遍历 n 个元素”?

核心原因有两个,结合上面的例子很容易理解:

  1. 子数组总长度不变:无论每趟的子数组长度是 1、2 还是 4,所有子数组的总长度始终是 n(因为合并只是 “组合子数组”,没有增加或减少元素);
  2. 合并需完整遍历子数组:要将两个有序子数组合并成一个有序数组,必须完整遍历这两个子数组的所有元素(否则无法保证合并后的数组有序)。因此,每趟合并时,所有子数组的元素都会被遍历一次,总遍历数就是 n。

第四步:延伸思考 ——n 不是 2 的幂时,是否仍满足 “每趟遍历 n 个元素”?

即使 n 不是 2 的幂(比如 n=7),结论依然成立。以 n=7 为例,合并阶段共 3 趟(log₂7≈2.8,向上取整为 3 趟):

  • 第 1 趟:7 个长度为 1 的子数组 → 合并 3 次(得到 3 个长度为 2 的子数组 + 1 个长度为 1 的子数组),总遍历元素数 = 2+2+2+1=7=n;
  • 第 2 趟:3 个长度为 2 的子数组 + 1 个长度为 1 的子数组 → 合并 2 次(得到 1 个长度为 4 的子数组 + 1 个长度为 2 的子数组 + 1 个长度为 1 的子数组?不,实际是 “优先合并同长度”,最终总遍历数仍为 7);
  • 第 3 趟:合并剩余子数组,总遍历数还是 7=n。

本质是:即使子数组长度不完全相同,每趟所有待合并子数组的总长度依然是 n,因此遍历的总元素数始终是 n

总结

“归并排序每一趟合并都遍历所有 n 个元素” 的核心逻辑可概括为:

  • 合并的本质是 “将当前所有有序子数组合并成更大的有序子数组”;
  • 所有子数组的总长度永远等于 n(元素没有增减);
  • 合并任意两个子数组都需要完整遍历它们的元素,因此每趟遍历的总元素数必然是 n。

这也是归并排序时间复杂度为 O (n log n) 的关键:共 log n 趟,每趟 O (n),总复杂度 O (n log n)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/22 1:33:58

Python入门篇【函数巩固题】

Python 银行账户管理系统&#xff08;简易版&#xff09; 文章目录Python 银行账户管理系统&#xff08;简易版&#xff09;概要需求描述代码概要 设计并实现一个简易银行账户管理系统&#xff0c;支持用户姓名校验、余额查询、存款、取款等核心功能&#xff0c;要求程序逻辑清…

作者头像 李华
网站建设 2026/9/22 0:25:26

23、互联网文件获取与网络冲浪全攻略

互联网文件获取与网络冲浪全攻略 在当今数字化的时代,从互联网获取文件、浏览网页以及检查网络连接是我们日常使用网络的常见操作。本文将为大家详细介绍通过 FTP 协议获取和分享文件、使用不同文本浏览器冲浪以及利用工具下载网站和检查连接的方法。 通过 FTP 从互联网获取…

作者头像 李华
网站建设 2026/9/22 2:09:55

28、Unix 系统超级用户操作指南

Unix 系统超级用户操作指南 在 Unix 系统中,普通用户权限有限,无法对系统造成整体损害,最多影响自己的文件。但存在一类特殊用户——超级用户(root),拥有系统的完全控制权,可处理配置问题、为所有用户安装软件以及进行故障排除,但一个小失误就可能破坏整个系统。下面为…

作者头像 李华
网站建设 2026/9/21 5:04:55

31、Unix 文件、目录与命令使用指南

Unix 文件、目录与命令使用指南 1. 引言 在使用 Unix 系统时,我们常常会遇到一些看似重要的文件和有趣的目录,但却很难知晓这些文件属于哪个程序,也难以搞清某些目录的用途。接下来将详细介绍 Unix 系统中的重要文件、目录以及常用命令和相关标志。 2. 重要 Unix 文件和目…

作者头像 李华
网站建设 2026/9/21 23:40:57

腾讯开源Hunyuan大模型系列:从边缘到云端的全场景AI解决方案

腾讯开源Hunyuan大模型系列&#xff1a;从边缘到云端的全场景AI解决方案 【免费下载链接】Hunyuan-7B-Pretrain 腾讯开源大语言模型Hunyuan-7B-Pretrain&#xff0c;支持256K超长上下文&#xff0c;融合快慢思考模式&#xff0c;具备强大推理能力。采用GQA优化推理效率&#xf…

作者头像 李华
网站建设 2026/9/21 14:43:08

15、Awk编程:表达式、系统变量及应用示例

Awk编程:表达式、系统变量及应用示例 1. 表达式基础 表达式在数据存储、操作和检索方面与sed有很大不同,但它是大多数编程语言的常见特性。表达式经过求值后会返回一个值,它由数字和字符串常量、变量、运算符、函数和正则表达式组合而成。 1.1 常量 常量有两种类型:字符…

作者头像 李华