当前课程知识点:数据结构(上) > 第二章 向量(下) > (f)归并排序 > 02F-6 归并排序:性能分析
这个二路归并算法的复杂度
主要应该消耗于其中的那个for循环
为了更好的进行分析
我们不妨把这个循环在此默写一遍
整体的是一个for循环
它的初始化 我们暂时可以忽略掉
最重要的是 这里通过或
连接起来的一个条件判断
总共有两部分组成
第一部分是说左侧
那个子向量的长度控制变量j没有越界
对称地 后面那个是说
右边那个子向量的控制变量k没有越界
它们俩之间只要有一个没有越界
这个循环就会执行下去
那么这个循环会怎么执行呢?
内部无非是两个并列的if语句
它们的逻辑判断 我们刚才已经看到了
相对比较复杂
但是好在我们有很简明的语义解释
也就是说 无论是相对于实在的元素
还是相对于虚拟的哨兵
只要B当前的那个元素更小
我们就将它取出来
并且转移到A中去
对称地 如果C当前的元素可以认为是更小
那么我们也把它取出
同样地转移到A中去
所以我们说 整体这个算法的流程无非如此
那我们可以注意到
这里棘手的地方在于
同时有两个控制变量j和k
我们不妨先来分析一下
我们看到 在初始的情况下
j和k都是初始化为零
那么最终的条件呢?
在这个算法退出的时候呢?
这两个条件都需要违反
也就是 j要一直增加 直到抵达lb
k也一直要增加 抵达到lc
所以我们知道 在退出的时候
必然有j和k分别取值就是lb和lc
换而言之 在这个时候
它们的总和是lb加上lc
也就是两个子序列的长度之和
好 我们这里注意到了j+k
没错
这个东西就是我们打开下面大门的钥匙
这样一个循环 虽然我还不确切地知道
它需要执行多少次
但是我可以知道它的一个上限
因为我们可以注意到
每经过一次迭代
两个if语句中 至少有一句会执行
当然有可能会执行两句
但是至少会有一句执行
每执行第一句 j就必然会自加
每执行第二句 k也会自加
所以我们得出一个结论
每经过一次迭代
j和k之间至少有一个会增加
或者笼统地来说
我们刚才所说的那个观察量j+k
也至少会增加一个单位
那这说明什么呢?
我们刚刚看到过
j+k在最初的时候是0
而最终的时候 无非就是n
作为一个整数
j+k这个观察量
从0开始 随着迭代的进行
不断地递增而且是严格地递增
每次至少增加一个单位
所以我们自然可以得出结论
这种迭代至多只会经过n次
换而言之 这个二路归并的merge算法
在最坏的情况下
也只需要线性次的时间
那么相应地来说 基于这样的一个二路归并
所实现的归并排序
它的算法复杂度是多少呢?
那么我们根据此前所写的那个递推式
也就是 如果要去用
归并排序求解一个n个元素的排序问题的话
相当于去递归地
对两个规模分别为
二分之n的子序列进行排序
然后至关重要的是在这儿
按照刚才的推断
只需要最多O(n)的时间
就可以将它们归并起来
这样一个解将得到
在大O意义下的n*logn的一个算法
我们要注意 这是在最坏情况下
也能够做到的一个结果
我们在此再次提醒大家注意
二路归并这个算法
其实是可以处理更一般的情况的
比如说 待归并的两个子序列
不仅不必像刚才所说的那样
必须互相紧邻的排列
而且它们在长度上也是不必相等的
它们可能有差别
甚至差别非常悬殊
但是这个算法总体只消耗它们累计长度
也就是线性这么多时间的结论
是不受影响的
依然成立
这个算法也可以很方便地、很自然地
推广到另一大类的序列
也就是与向量对称的列表
我们在下一章中呢 将会介绍这种数据结构
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-OJ系统说明
--关于OJ
--1-注册与登录
--2-界面与选课
--3-提交测试
-关于课程教材与讲义
--课程教材与讲义
-关于讨论区
--关于讨论区
-微信平台
--html
-PA晋级申请
--PA晋级
-(a)计算
--演示
--(a)计算--作业
-(b)计算模型
-(b)计算模型--作业
-(c)大O记号
-(c)大O记号--作业
-(d)算法分析
-(d)算法分析--作业
-(e)迭代与递归
-(e)迭代与递归--作业
-(xc)动态规划
-- 演示
-(xc)动态规划--作业
-本章测验--作业
-(a)接口与实现
--02A-5 复制
-(a)接口与实现--作业
-(b)可扩充向量
-(b)可扩充向量--作业
-(c)无序向量
--02C-1 概述
--02C-3 插入
--02C-6 查找
--02C-8 遍历
-(c)无序向量--作业
-(d1)有序向量:唯一化
-(d1)有序向量:唯一化--作业
-(d2)有序向量:二分查找
-(d2)有序向量:二分查找--作业
-(d3)有序向量:Fibonacci查找
-(d3)有序向量:Fibonacci查找--作业
-(d4)有序向量:二分查找(改进)
-(d4)有序向量:二分查找(改进)--作业
-(d5)有序向量:插值查找
-第二章 向量(下)--(d5)有序向量:插值查找
-(e)起泡排序
--02E-2 改进
--02E-3 反例
-(e)起泡排序--作业
-(f)归并排序
-(f)归并排序--作业
-本章测验--作业
-(a)接口与实现
--03A-4 实现
-(a)接口与实现--作业
-(b)无序列表
--03B-2 查找
-(b)无序列表--作业
-(c)有序列表
--03C-3 查找
-(c)有序列表--作业
-(d)选择排序
--03D-1 构思
--03D-2 实例
--03D-3 实现
--03D-4 推敲
--03D-6 性能
-(d)选择排序--作业
-(e)插入排序
--03E-1 经验
--03E-2 构思
--03E-3 对比
--03E-4 实例
--03E-5 实现
-(e)插入排序--作业
-(xd)习题辅导:LightHouse
-本章测验--作业
- (a)栈接口与实现
--04A-1 栈
--04A-2 实例
--04A-3 实现
- (a)栈接口与实现--作业
-(c1)栈应用:进制转换
-第四章 栈与队列--(c1)栈应用:进制转换
-(c2)栈应用:括号匹配
-(c2)栈应用:括号匹配--作业
-(c3)栈应用:栈混洗
-第四章 栈与队列--(c3)栈应用:栈混洗
-(c4)栈应用:中缀表达式求值
-(c4)栈应用:中缀表达式求值--作业
-(c5)栈应用:逆波兰表达式
-第四章 栈与队列--(c5)栈应用:逆波兰表达式
-(d)队列接口与实现
--04D-1 接口
--04D-2 实例
--04D-3 实现
-第四章 栈与队列--本章测验
-(a)树
--05A-1 动机
--05A-2 应用
-(a)树--作业
-(b)树的表示
--05B-2 父亲
--05B-3 孩子
-第五章 二叉树--(b)树的表示
-(c)二叉树
-(c)二叉树--作业
-(d)二叉树实现
-(d)二叉树实现--作业
-(e1)先序遍历
-(e1)先序遍历--作业
-(e2)中序遍历
-第五章 二叉树--(e2)中序遍历
-(e4)层次遍历
-第五章 二叉树--(e4)层次遍历
-(e5)重构
-(e5)重构--作业
-本章测验--作业
-(a)概述
-(a)概述--作业
-(b1)邻接矩阵
-(b1)邻接矩阵--作业
-(c)广度优先搜索
--06C-2 策略
--06C-3 实现
--06C-5 实例
-(c)广度优先搜索--作业
-(d)深度优先搜索
--06D-1 算法
--06D-2 框架
--06D-3 细节
-(d)深度优先搜索--作业
-第六章 图--本章测验