当前课程知识点:数据结构(上) > 第二章 向量(下) > (f)归并排序 > 02F-5 二路归并:正确性
为了更好地理解 刚才那个算法的过程
我们不妨分几种情况 来给出具体的图示
同样 这是整个的_elem数据区
这是待归并的
两个子序列的公共的部分
以及最终要归并的内容
在算法的过程中
我们分别用i j k来指示
这三个子向量中的
当前我们所关注的那个元素
我们首先来考虑第一种情况
也就是 i还是介于lo和mi之间
没有越过mi这个界线
还没有进入到
C这个子向量的范围
这种情况 我们讲是很自然的
因为显然i不可能居于j的左侧
顶多是个平齐
所以每次迭代中
如果需要发生数据转移的话
无论是B[j]转移到A[i]
还是C[k]转移到A[i]
我们可以看出来 整个数据
从内容来讲 都不会发生覆盖
是安全的
功能上讲 也是正确的
再来看相对复杂一点的情况(b)
也就是当这个i在持续增加之后
终于有一天 会越过mi
进入C的区域
表面看 这样会侵犯到C的区域
但是我们说 实际上不要紧
因为在这个时候
k绝对不会位于i的左侧
所以 介于mi和i之间的这些元素
其实作为C中原来的元素
必然已经归入到A中
当然是它的左侧
在i之前的这部分中的
某一个适当的位置中去了
所以这种情况 表面看有点危险
但是我们说 依然是安全的
无论是C[k]、还是B[j]转移到A[i]中去
都不会导致C中已有的元素
被无意中覆盖掉
从而导致错误
我们再来看最后两种
更为复杂的情况
也就是 我们刚才所说的
有可能在某个时候
B这个子向量已经提前耗尽
具体来说 就是它其中的元素
已经完全地归入到A中
当然也是就位了
而在C中还残存有部分的元素
没有转移和就位
我们说 这种情况下
正如我们刚才所说的
我们的逻辑其实相当于等效地
是在B的最右侧
就是lb这个位置上
增加了一个哨兵节点
而且它的数值就是正无穷
因此即便C的右侧 还残存有若干个元素
它们也会在接下来的各次迭代中
因为是与这样一个正无穷相比
而被认为是更小
从而顺利地转移到A中适当的位置
直到两个子向量都同时耗尽
那么反过来 另一种对称的情况就是
C也可能会提前耗尽
同样正如我们此前所分析的那样
我们这里所给的逻辑
也相当于等效地 在C的最右侧
增加了一个数值为正无穷的哨兵
它的秩是lc
如果真发生这种情况的话
即便在B的尾部 还残存有部分的元素
我们说 也不要紧
它们也等效于
和这样一个数值为正无穷的哨兵相比
或者说 它们总是会被认为是更小
所以按照算法的逻辑
会等效地转移到A中
剩余的对应区域中去
整个这个过程也是会顺利地进行
不会出现我们所说的数据遗漏
或者数据被无意中覆盖
细心的同学可能已经注意到了
(c)和(d)这两种情况其实并不对等
因为按照我们这里的设计
其实向量C和B 地位本来就是不等的
B是完全复制出来的一个缓冲部分
而C虽然是独立的绘制出来
但实际上它就在A中 占据右端
换而言之 如果是C提前耗尽
我们确实需要把B尾部的这些元素
悉数转移到A的尾部
但如果是B提前耗尽
那么对C尾部这些元素的转移
其实都是多余的
因为它们原来就在那
完全没有必要
注意到这样一个现象的话
我们就不难对刚才表面上很规范的逻辑
进一步的精简
也就是说将我们这里所有的灰色部分
都给它抹去
这个括号 这个括号以右
以及这个逻辑
当然也包括这对括号
还有这个逻辑和这个逻辑
那么这里最最重要的其实就是这个部分
就像我们刚才所说的
我们并不需要考虑C提前耗尽的那种情况
我们只需要考虑B提前耗尽的那种情况
一旦B提前耗尽
我们就可以直接终止这个循环包括这个算法
所以这样的话
可以使这个算法效率进一步的提高
尽管不是从渐进角度而言的一种实质的提高
那么这个算法在原来
以及包括这样精简之后
从渐进意义上讲 复杂度是多少呢?
是否能像我们最初所预期的那样
能够有大幅度的提高呢?
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-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)深度优先搜索--作业
-第六章 图--本章测验