数据结构二叉树(五)
线索二叉树的定义
对于n个结点的二叉树,在二叉链存储结构中有n+1个空链域。
利用这些空链域存放在某种遍历次序下该结点的前驱结点和后继结点的指针,这些指针称为线索,加上线索的二叉树称为线索二叉树。
线索二叉树分为先序、中序和后序线索二叉树。
对二叉树以某种方式遍历使其变为线索二叉树的过程称为线索化。
在原二叉链中增加了ltag和rtag两个标志域。
以中序线索二叉树为例
线索化二叉树
中序线索化二叉树类ThreadTree
采用中序遍历进行中序线索化
在整个算法中p总是指向当前访问的结点,pre指向其前驱结点。
遍历线索化二叉树
该算法是一个非递归算法,算法的时间复杂度为O(n),空间复杂度为O(1)
哈夫曼树的定义
给定4个叶子结点,设其权值分别为1、3、5、7,可以构造出形状不同的4棵二叉树。
哈夫曼树的构造算法
(1)根据给定的n0个权值W=(w1,w2,…,wn0),对应结点构成n0棵二叉树的森林T=(T1,T2,…,Tn0),其中每棵二叉树Ti(1≤i≤n0)中都只有一个带权值为wi的根结点,其左、右子树均为空。
(2)在森林T中选取两棵根结点权值最小的子树作为左、右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左、右子树上根的权值之和。称为合并,每合并一次T中减少一棵二叉树。
(3)重复(2)直到T只含一棵树为止。这棵树便是哈夫曼树。
每次都是两棵子树合并 ð 哈夫曼树中没有单分支结点
W=(1,3,5,7)来构造一棵哈夫曼树
定理6.3 对于具有n0个叶子结点的哈夫曼树,共有2n0-1个结点。
证明:从哈夫曼树的构造过程看出,每次合并都是将两棵二叉树合并为一个,所以哈夫曼树不存在度为1的结点,即n1=0。
由二叉树的性质1可知n0=n2+1,即n2=n0-1
则结点总数n=n0+n1+n2= n0+n2=n0+2n0-1=2n0-1。
构造哈夫曼树中采用静态数组ht存储哈夫曼树,即每个数组元素存放一个结点。设计哈夫曼树中结点类如下:
哈夫曼编码
构造一棵哈夫曼树。
规定哈夫曼树中的左分支为0,右分支为1。
从根结点到每个叶子结点所经过的分支对应的0和1组成的序列便为该结点对应字符的编码。这样的编码称为哈夫曼编码。
哈夫曼编码的实质就是使用频率越高的采用越短的编码。
只有ht[0..n0-1]叶子结点才对应哈夫曼编码,用hcd[i](0≤i≤n0-1)表示ht[i]叶子结点的哈夫曼编码。
输出所有叶子结点的哈夫曼编码的算法
输出ht的算法
在一组字符的哈夫曼编码中,任一字符的哈夫曼编码不可能是另一字符哈夫曼编码的前缀。
树到二叉树的转换及还原
树到二叉树的转换
一棵树可以按照以下规则转换为二叉树:
加线:在各兄弟结点之间加一连线,将其隐含的“兄-弟”关系以“双亲-右孩子”关系显示表示出来。
抹线:对任意结点,除了其最左子树之外,抹掉该结点与其他子树之间的“双亲-孩子”关系。
调整:以树的根结点作为二叉树的根结点,将树根与其最左子树之间的“双亲-孩子”关系改为“双亲-左孩子”关系,且将各结点按层次排列,形成二叉树。
根结点只有左子树而没有右子树。
左分支不变(左分支为最左孩子),兄弟变成右分支(右分支实为双亲的兄弟)。
树中分支结点个数为m,则二叉树中无右孩子的结点个数为m+1。这里m=4。
一棵由树转换的二叉树还原为树
一棵二叉树(由一棵树转换的)可以按照以下规则还原为一棵树:
加线:在各结点的双亲与该结点右链上的每个结点之间加一连线,以“双亲-孩子”关系显示表示出来。
抹线:抹掉二叉树中所有双亲结点与其右孩子之间的“双亲-右孩子”关系。
调整:以二叉树的根结点作为树的根结点,将各结点按层次排列,形成树。
根结点不变。
左分支不变(左分支为最左孩子),右分支变成兄弟。
森林到二叉树的转换及还原
森林转换为二叉树
含有两棵或两棵以上树的森林可以按照以下规则转换为二叉树:
转换:将森林中的每一棵树转换成二叉树,设转换成的二叉树为bt1、bt2、…、btm。
连接:将各棵转换后的二叉树的根结点相连。
调整:以bt1的根结点作为整个二叉树的根结点,将bt2的根结点作为bt1的根结点的右孩子,将bt3的根结点作为bt2的根结点的右孩子,…,如此这样得到一棵二叉树,即为该森林转换得到的二叉树。
二叉树还原为森林
当一棵二叉树的根结点有m-1个右下孩子,这样还原的森林中有m棵树。这样的二叉树可以按照以下规则还原其相应的森林:
抹线:抹掉二叉树根结点右链上所有结点之间的“双亲-右孩子”关系,分成若干个以右链上的结点为根结点的二叉树,设这些二叉树为bt1、bt2、…、btm。
转换:分别将bt1、bt2、…、btm二叉树各自还原成一棵树。
调整:将转换好的树构成森林。