科大C语言笔记-2
哈夫曼树的基本概念
最优二叉树,也称哈夫曼(Haffman)树,是指对于一组带有确定权值的叶结点,构造的具有最小带权路径长度的二叉树
给出4 个叶结点,设其权值分别为1,3,5,7,我们可以构造出形状不同的多个二叉树。这些形状不同的二叉树的带权路径长度将各不相同。
这五棵树的带权路径长度分别为:
(a)WPL=1×2+3×2+5×2+7×2=32
(b)WPL=1×3+3×3+5×2+7×1=29 //根节点开始,从0到叶节点经历了几就乘几,再求和
(c)WPL=1×2+3×3+5×3+7×1=33
(d)WPL=7×3+5×3+3×2+1×1=43
(e)WPL=7×1+5×2+3×3+1×3=29
下图:给出了前面提到的叶结点权值集合为W={1,3,5,7}的哈夫曼树的构造过程。可以计算出其带权路径长度为29,由此可见,对于同一组给定叶结点所构造的哈夫曼树,树的形状可能不同,但带权路径长度值是相同的,一定是最小的。
二叉树的相关概念
(1)结点的度。结点所拥有的子树的个数称为该结点的度。
(2)叶结点。度为0 的结点称为叶结点,或者称为终端结点。
(3)分枝结点。度不为0 的结点称为分支结点,或者称为非终端结点。一棵树的结点除叶结点外,其余的都是分支结点。
(4)左孩子、右孩子、双亲。树中一个结点的子树的根结点称为这个结点的孩子。这个结点称为它孩子结点的双亲。具有同一个双亲的孩子结点互称为兄弟。
(5)路径、路径长度。如果一棵树的一串结点n1,n2,…,nk 有如下关系:结点ni 是ni+1的父结点(1≤i<k),就把n1,n2,…,nk 称为一条由n1 至nk 的路径。这条路径的长度是k-1。
(6)祖先、子孙。在树中,如果有一条路径从结点M 到结点N,那么M 就称为N的祖先,而N 称为M 的子孙。
(7)结点的层数。规定树的根结点的层数为1,其余结点的层数等于它的双亲结点的层数加1。
(8)树的深度。树中所有结点的最大层数称为树的深度。
(9)树的度。树中各结点度的最大值称为该树的度。
(10)满二叉树:在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子结点都在同一层上,这样的一棵二叉树称作满二叉树。
(a)图就是一棵满二叉树,(b)图则不是满二叉树,因为,虽然其所有结点要么是含有左右子树的分支结点,要么是叶子结点,但由于其叶子未在同一层上,故不是满二叉树。
完全二叉树。
一棵深度为k 的有n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。完全二叉树的特点是:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。如图6.3 所示(a)为一棵完全二叉树,(b)和图6.2(b)都不是完全二叉树。
基本操作与存储—二叉树的存储
1.顺序存储结构
所谓二叉树的顺序存储,就是用一组连续的存储单元存放二叉树中的结点。一般是按照二叉树结点从上至下、从左到右的顺序存储。这样结点在存储位置上的前驱后继关系并不一定就是它们在逻辑上的邻接关系,然而只有通过一些方法确定某结点在逻辑上的前驱结点和后继结点,这种存储才有意义。因此,依据二叉树的性质,完全二叉树和满二叉树采用顺序存储比较合适,树中结点的序号可以唯一地反映出结点之间的逻辑关系,这样既能够最大可能地节省存储空间,又可以利用数组元素的下标值确定结点在二叉树中的位置,以及结点之间的关系。
对于一般的二叉树,如果仍按从上至下和从左到右的顺序将树中的结点顺序存储在一维数组中,则数组元素下标之间的关系不能够反映二叉树中结点之间的逻辑关系,只有增添一些并不存在的空结点,使之成为一棵完全二叉树的形式,然后再用一维数组顺序存储。
2.链式存储结构
所谓二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示着元素的逻辑关系。通常有下面两种形式。
(1)二叉链表存储
链表中每个结点由三个域组成,除了数据域外,还有两个指针域,分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。结点的存储的结构为:
其中,data 域存放某结点的数据信息;lchild 与rchild 分别存放指向左孩子和右孩子的指针,当左孩子或右孩子不存在时,相应指针域值为空(用符号∧或NULL 表示)。