当前课程知识点:数据结构(上) > 第二章 向量(下) > (f)归并排序 > 02F-4 二路归并:实现
这里所给的就是二路归并算法的一种实现
正如刚才所言
这里需要将定义两个向量的三个界桩
也就是lo、mi和hi作为参数传入
接下来 我们要定义清楚ABC三个向量
首先A向量在这里
将继续地保存在它输入的位置
准确地讲 就是在_elem这个整个数据区中
起自于最左侧的界桩lo的这么样一段区间
这也就是为什么我们可以
直接令A指向这个区间的起点
好 接下来是左侧的子向量B
我们需要为这个子向量申请一段空间
它的宽度应该就是mi到lo之间的距离
这也是为什么我们在这里
相应的申请这么大的一段空间
当然接下来 我们还需要将A中
对应的那些元素
也就是左半部分的那些元素
逐一地取出来并且复制到
新开辟的这段空间中去
从而完成整体的这个子向量B的一个缓冲
好 C呢?
我们看到C非常的简单
实际上 定义的就是
在_elem数据区中
起始于mi的这段数据
那么不同的在于右侧的子向量C
并不需要另辟空间进行缓存
尽管在这里 为了说明的方便
我们还是将它画在了上边
作为一个单独的子向量
好 接下来
就开始了我们最主要的这个循环
这也就是刚才
我们的例子所给的过程
具体来讲就是
每一次我们都比较
两个子向量当前的首元素
取出其中更小的那个
比如说 在这种情况下 B更小
而在下一种情况下 C更小
无论谁更小 我们都把它转入到A中去
而这个首元素是由谁来标定的呢?
可以看到是由j和k
这两个秩来标定的
在最初始的情况下
它们都是0
分别指向B和C的第一个元素
在随后 每当有一个元素转移到A中
它们各自都会自加
从而指向下一个替补的新的首元素
而A中每次纳入的那个元素
又是由谁来指示的呢?
可以看到 是由i来指示的
同样 i最初初值也是0
而每次接纳了一个元素之后
它自己也会通过自加
指向下一个适当的位置
细心的同学可能已经注意到
我们在这里头有相对更复杂的逻辑
尽管从形式上看 显得比较紧凑
我们不妨来进一步地解读它
我们可以看到 所谓B更小的情况
严格的讲 是由一系列的逻辑判断构成的
准确的说 首先是一个and
是一个与
也就是说 我们要确定j小于lb
也就是说 B中这个所谓的首元素的秩
应该至少没有越过它的右侧的边界
它还是合法的
换而言之 这个时候
B[j]指向的还是一个实在的
而不是虚拟的元素
接下来地 有两种情况
要么这个k已经越界
要么就是可以理解为 这个k没有越界
但是它作为一个实在的元素
比另一个实在的首元素不小
大家注意 这里我们运用了
C++语言里头的“短路求值”的语法特性
否则的话
这个不满足的情况下
我们还去对这个进行比较求值
实际上 这个k因为已经越界
就会造成程序运行过程中的错误
那么k大于lc
也就是它越界的时候
为什么我们可以理解成
是将它的那个实在的对手转移出去呢?
我们说 为了把这两个逻辑统一起来
很好的一个做法
也是我们这门课中常用的一个技巧
就是假想着 在C的末尾添加了一个哨兵
而且将它的数值假设为是正无穷
那么现在我们就很好理解这句话了
或者 与其说是k越界
不如说 C[k]这个元素已经是正无穷了
那么作为正无穷来说
任何实在的元素B[j]都不可能比它大
所以这个情况下
我们把B转移到A中去
也是符合这个语义的
这样的话 我们就非常好想象了
那么同样地
我们也可以考虑在B的末尾
缀上一个数值为正无穷的哨兵节点
这样 我们也可以很好地来解释第二条if语句
那么它的意思是说
j一旦超出了B的右边界
也就是 它实际上是一个哨兵
那么其实也等效于这样一个判断
也就是说 作为一个实在的C中的一个元素
和这样一个数值为正无穷的元素比
必然是更小的
所以这个时候或者是这个时候
统一地都可以将C视作是更小的元素
转移至A中去
当然整个这个循环的退出条件也值得揣摩的
我们看到 这里的条件
可以理解为是
或者j已经越出它的边界非法
或者是k越出它的边界非法
我们可以 这两个条件是或的关系
而不是像通常的理解那样 是与的关系
所以从这里我们也可以看得出来
这个算法所终止的条件是
这两个位置j和k
同时越界之后 这个算法才会退出
而在这个时候 无论是B还是C中的元素
都已经完整地归入到了A中
成为了一个整体的序列
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-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)深度优先搜索--作业
-第六章 图--本章测验