线索化二叉树的认识
空链域的出现
- 对于具有n个节点的二叉树,采用链式存储结构时,每个节点有两个指针域,总共有2n个指针域
- 同时又由于只有n-1个节点被有效指针所指向(只有根节点没有被指向)
-
所以共有2n-(n-1)=n+1个空链域
线索:
我们知道遍历二叉树的结果是一个节点的线性序列,所以可以利用上面的空链域来存储指向节点的前驱节点和后继节点,这样的指向该线性序列中的前驱节点和后继节点的指针,称为线索。
线索二叉树
每个节点加上线索的二叉树叫做线索二叉树
规则:
- 当某节点的左指针为空时,就令该指针指向按某种方式遍历二叉树时得到的该节点的前驱节点
- 当某节点的右指针为空时,就令该指针指向按某种方式遍历二叉树时得到的该节点的后继节点
存储结构:
在节点的存储结构中增加两个标志位来区分左指针指向的节点到底是左孩子节点还是前驱节点,右指针同理
左标志ltag:
- ltag == 0 表示lchild指向左孩子节点
- ltag == 1 表示lchild指向前驱节点
右标志rtag:
- rtag == 0 表示lchild指向右孩子节点
- rtag == 1 表示lchild指向后继节点
优缺点:
优点:
- 提高利用率,利用了被浪费的n+1个空链域
- 提高遍历速度,存放线索,可以方便的查找前驱节点和后继节点
缺点:
- 节点的插入和删除麻烦,且速度也比较慢
- 线索子树不能共用
二叉树的线索化
对一个二叉树以某种方式遍历使其变为线索二叉树的过程就叫做二叉树的线索化
过程:
1、检查当前节点的左、右指针域是否为空
2、如果为空,将他们改为指向前驱节点或后继节点
3、创建一个头节点,并建立头节点和根节点之间的线索
线索化二叉树的遍历
介绍
遍历某种次序的线索二叉树,就是从该次序下的开始节点出发,找到当前节点在该次序下的后继节点,直到终端节点。
注:查找先序/后序前驱节点必须要知道该节点的双亲节点,而二叉链表中没有存放指向双亲的指针,因此实际使用中很少用到先序/后序线索二叉树,下面使用的是 中序线索二叉树分析
哈夫曼树的介绍
带权路径长度: 在许多应用中,常常将树中的节点赋上一个有某种意义的数值,称此数值为该节点的权,从树根节点到某节点之间的路径长度与该节点上权值的乘积称为该节点的带权路径长度。
WPL: 树中所有叶子节点的带权路径长度之和称为该树的带权路径长度,记为WPL
在n个带权叶子节点构成的所有二叉树中,带权路径长度WPL最小的二叉树称为哈夫曼树。
带权路径长度计算
1、WPL = 1 * 2 + 3 * 2 + 5 * 2 + 7 * 2 = 32
2、WPL = 1 * 2 + 3 * 3 + 5 * 3 + 7 * 1 = 33
3、WPL = 7 * 3 + 5 * 3 + 5 * 2 + 1 * 1 = 43
4、WPL = 1 * 3 + 3 * 3 + 5 * 3 + 7 * 1 = 29
经过计算发现第四个二叉树是哈夫曼树
可以具有确定权值的叶子节点可以构造出多个具有不同带权路径长度的二叉树,其中值最小的二叉树叫做哈夫曼树,这里第四个二叉树就是哈夫曼树
哈夫曼树的构造
给定n个权值,如何构造一棵含有n个给定权值的叶子节点的二叉树,使其带权路径长度WPL最小呢?
1、先将这n个权值作为带权值的根节点,左右子树均为空
2、选取权值最小的两颗树,分别作为左右子树构造一棵新的二叉树,其根节点的权值为左右子树根节点的权值之和
3、重复2步骤,直到把所有的节点都放到树上
注意:
- 之前给定的权值,全都在叶子节点上,分支节点必须是叶子节点计算出来的结果
- 权值越小的节点所在的层次越深
哈夫曼树的节点
{
char data;//节点值
double weight;//权重
int parent;//双亲节点
int lchild;//左孩子节点
int rchild;//右孩子节点
}
说明:
- 为了方便的构造双亲节点,所以需要保存双亲节点
- 为了计算权值,还需要加上本节点的权重信息
哈夫曼编码
来源:
在数据通信中,经常需要将传送的文字转换为二进制字符0和1组成的字符串,这个过程称为编码,显然,我们希望电文编码的代码长度最短,而通过哈夫曼树可以把电文编码的代码长度构造为最短。
实质: 哈夫曼编码的实质就是使用频率越高的字符采用越短的编码
构造方式:
- 规定哈夫曼树中的左节点为0,右节点为1,
- 则从根节点到每个叶子节点所经过的分支对应的0和1组成的序列便为该节点对应字符的编码
- 这种编码方式就是哈夫曼编码
编码效果:
- 出现次数较多的字符处于树的上方,这个字符的编码程度就短
- 而且出现次数较多的元素编码长度短,出现次数较多的元素编码长度长,可以起到压缩效果
- 因为可以根据编码长度来进行存储,而不是直接开辟最大的存储空间
- 这样当有些字符并不需要这么大空间的时候就引起了浪费
优点:
- 避免浪费空间,起到压缩效果,因为可以根据编码长度的大小来确定存储空间
- 解决多义性问题,因为所有的叶子节点都是唯一的
总结:
- 哈夫曼树就是所有叶子节点的带权路径最小的树,也叫做最优二叉树
- 构造哈夫曼树的原理就是将权值最小的叶子节点放在最深层,权值越高的层级越小
- 哈夫曼编码可以将使用频率越高的字符采用越短的编码
- 具体做法就是将左节点作为0,右节点作为1,进行哈夫曼树构造