create dsa chp5 conclusion chp5.md.

This commit is contained in:
Shine wOng
2019-06-01 15:11:22 +08:00
parent a8e4f7f8c6
commit 3928c7ff9a

87
thu_dsa/chp5/chp5.md Normal file
View File

@@ -0,0 +1,87 @@
Conclusion on Chapter Five: Binary Tree
=======================================
## 树形结构
> 什么是树形结构?
树是一种分层结构。而客观世界中很多事物都采取分层结构,例如域名,例如文件系统,例如家谱树,因此树可以在世界中有大量的应用。
和线性结构相比,树是一种半线性结构。这是因为树的每一个结点都是一个入度,多个出度。而线性结构如`Vector`或者`List`的每一个元素都是一个入度,一个出度,所以说树是半线性结构。另一方面,树的若干表示形式中,都蕴含了线性结构,例如邻接链表的表示中,每个结点的子结点形成了一个邻接链表,整棵树是有多个这样的线性的邻接链表组成,所以树是半线性结构。此外,在孩子兄弟表示法中,所有的孩子可以组成从根节点到叶节点的一个链表,每棵树也含有多个这样的链表,也构成了半线性结构。
从图的理论来讲树是连通无环图。更详细地说来是含有n个结点的最大无环图和最小连通图。
> 树的性质(深度和高度)。
树作为数据结构自然具有一些性质。例如像是入度出度这种,还有祖先结点父节点子结点,自不多言。
这里关键是对树的深度和高度做一个约定。树的深度从树根开始算起,并且树根的深度为零。树的高度从最低的叶节点开始算起,并且叶节点的高度为零。约定空树(`null`)的高度为-1。
## 二叉树
> 树与二叉树的区别与联系?
顾名思义,二叉树是树的一种特殊形式。但是二叉树又可以表示所有的树。这是因为在树的孩子兄弟表示法中,将某个结点的孩子指针作为它的左子树,将它的下一个兄弟指针作为它的右子树,通过这样的方式,可以将任意一棵一般的树表示成为一棵二叉树。
### 二叉树的一个实例:编码树
> 什么是编码树?
编码树其实是将编码的过程用一棵二叉树来表示。如果是将字符集进行二进制编码的话就是对应二叉树否则就是k叉树k为编码的进制。
可以对编码树进行一些约定,例如对于二叉编码树,站在某个子树的根节点上,向左走是零,向右走是一,这样就可以通过沿着该编码树的一条路径行走,得到某个字符的二进制码值。
> 什么是前缀无歧义编码(PFC, Prefix-Free Code)
考察一个例子,例如字符`M`被编码成二进制串`011`,而字符`N`被编码成二进制串`0110`。这样,在解码时,就有可能产生冲突。比如对于码串`011011...`,既可以将前三个`011`解码成`M`,也可以选择将前四个`0110`解码成`N`,这就是前缀有歧义编码。从二叉编码树的角度来看,这因为`M``N`处于二叉编码树的同一条路径上。究其根源,还是因为它们的前缀部分有冲突,一个字符的编码前缀是另一个字符的编码结果。
前缀无歧义编码就是相对上面的例子而言。要实现前缀无歧义编码,就是要避免编码的字符对应的二进制编码串,相互之间不得是前缀。要实现这个条件,其实就是使每个编码的字符在编码树上对应一个叶节点。这样,由于对于一棵树而言,从根节点到任意叶节点的路径唯一,解码过程也不再会出现歧义。在上面的例子中,出现的问题就是`M`并不是编码树的叶节点,而是`N`的父亲结点。
> 最优编码树。
即使做到了前缀无歧义编码,也还有众多编码方案。这么多的编码方案中应该如何选择呢?这就涉及到衡量不同编码方案的优劣。
在通信理论中,主要是考虑信息的传输效率。这样,如果针对同一个文本信息,某一个编码方案编码后得到的二进制码长度更小,那么这显然是一个更优的编码方案。最优编码树,就是对应这样一个最短的二进制码长度编码方案的编码树。
这里的一个衡量编码长度的指标是平均编码长度,也就是编码树中的叶节点平均深度(alp, average leaf depth)。所以最优编码树就是在所有的编码方案中拥有最小的ald指标的一棵编码树。
> 最优编码树的性质。
双子性。这应该是是比较明显的,因为如果有一个结点只有一个子结点,就是说在这个结点处不存在`0`还是`1`的左右跳转,那么这个结点的编码是冗余的,所以完全可以用它的唯一子结点来代替这个结点,便可以获得一棵更优的编码树。
层次性。这是说所有的叶节点的深度相差不超过1也就是说这棵编码树具有良好的平衡性。这也是可以理解的(严格证明也可以,这里略过),因为只有保持良好的平衡性,叶节点才具有更小的平均深度,因为此时具有最小的树高。
> 最优编码树的构造。
从上面的讨论看出最优编码树的一个例子就是完全二叉树。因此对于任意一个含有n个字符的字符集可以直接构造一棵具有$2n - 1$个结点的完全二叉树,这即是一棵最优编码树。
从上面的讨论也可以看出,最优编码树并不是唯一的。这里的完全二叉树方案只是其中的一种。
> 关于完全二叉树。
完全二叉树具有一些良好的性质,这里做一个简单的说明。
对于任意一棵完全二叉树,在其层次遍历过程中,前$[\frac{n}{2}]$次迭代都有左孩子入队,且前$[\frac{n}{2}] - 1$次迭代都有右孩子入队。实际上,这也是完全二叉树的定义。现证明如下:
对于任意一棵完全二叉树,设其度为零、一、二的结点个数分别为$N_0, N_1, N_2$,所以总结点个数
$$
N = N_0 + N_1 + N_2
$$
该完全二叉树中的路径的条数满足
$$
N_1 + 2N_2 = N - 1 = N_0 + N_1 + N_2 - 1
$$
整理可以得到
$$
N_2 = \frac{N - N_1 -1}{2}
$$
$$
N_0 = \frac{N + 1 - N_1}{2}
$$
从而可以得到上面的结论。
这样,我们就可以理解,为什么上面最优编码树的构造可以直接取总结点的数量$N = 2N_0 - 1$了,这是因为对于编码树而言,根据其双子性,编码树不具有度为一的结点。所以$N_0 = \frac{N + 1}{2}$,从而可以得到$N = 2N_0 - 1$。
此外对于二叉编码树任意第k个结点从一开始编号的左孩子是第2k个结点右孩子是第2k+1个结点如果左右孩子都存在的话。证明如下
设当前第k个结点至少有左子树高度为h所以本层在当前结点前面的结点有$k - 2^{h}$个,换算到下一层在当前结点左子结点前面的结点就有$2·(k - 2^{h})$个。本层在当前结点后面的结点有$2^{h+1} - 1 - k$个,这样在当前结点和子结点直接就相隔了$2·(k - 2^{h}) + 2^{h+1} - 1 - k = k - 1$个路人,所以当前结点的左结点位于第$2k$个,右节点在第$2k + 1$个。