当前位置:文档之家› 树与森林的遍历

树与森林的遍历


第十七讲
∑p ×I
i =1 i
7
i
= 0.40 × 1 + 0.30 × 2 + 0.15 × 3 + 0.05 × 5 + 0.04 × 5 + 0.03 × 5 + 0.03 × 5 = 2.20
第十七讲
举例:数据传送中的二进制编码。 要传送数据 state, seat, act, tea, cat, set, a, eat, 如何使传 送的长度最短? 首先规定二叉树的构造为左走0,右走1 ,如图6.31所示。 为了保证长度最短, 先看字符出现的次数, 然后将出现 次数当作权, 如图6.32所示。
第十七讲
2. 森林的遍历 森林的遍历 森林的遍历方法主要有以下三种: 1) 先序遍历 若森林非空, 则遍历方法为: (1) 访问森林中第一棵树的根结点。 (2) 先序遍历第一棵树的根结点的子树森林。 (3) 先序遍历除去第一棵树之后剩余的树构成的森林。 例如, 图6.24(a)中森林的先序遍历序列为ABCDEFGHIJ。
第十七讲 作业:
1.二叉树的层次遍历算法(二叉链表存储); 2.求二叉树中最大结点值(二叉链表存储)。
第十七讲
哈夫曼树及其应用
第十七讲
1. 哈夫曼树
1. 路径和路径长度 路径和路径长度 路径是指从一个结点到另一个结点之间的分支序列, 路径 路径长度是指从一个结点到另一个结点所经过的分支数目。 路径长度 树的路径长度是从树根到每一结点的路径长度之和。 树的路径长度
图6.30 构造哈夫曼树示例
第十七讲
表 6 – 3 指令的哈夫曼编码
指令 I1 I2 I3 I4 I5 I6 I7 使用频率(Pi) 0 10 110 11100 11101 11110 11111
可以验证,该编码是前缀编码。若一段程序有1000条指令, 其中I1 大约有400条,I2 大约有300条,I3 大约有150条,I4 大约 有50条,I5大约有40条,I6大约有30条,I7大约有30条。对于定 长编码,该段程序的总位数大约为3×1000=3000。采用哈夫 曼 编 码 后 , 该 段 程 序 的 总 位 数 大 约 为 1×400 + 2×300 + 3×150+5×(50+40+30+30)=2200。可见,哈夫曼编码 中虽然大部分编码的长度大于定长编码的长度3, 却使得程序 的总位数变小了。可以算出该哈夫曼编码的平均码长为:
第十七讲
(2) 将所有字符变成二进制的哈夫曼编码, 使带权路径长 度最短,相当总的通路长度最短。 若要求传送以上这些编码长度不一的数据, 且还要求传 送词间互相区分,应如何设计最优编码呢? 为保证传送词间 互相区别,则需加入一空白字符出现频率, 空白字符^出现为 7, 再构造哈夫曼树,由此得到的哈夫曼编码一定满足最短且 又互相区分的性质。 c 2 s 3 e 5 a 7 ^ 7 t 8
第十七讲
HuffmanTree CrtHuffmanTree(HuffmanTree *ht , *HuffmanCode , *hc, int * w, int n) {/*w存放n个权值, 构造哈夫曼树ht, 并求出哈夫曼编码hc */ HuffmanTree ht; m=2*n-1; ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); /*0号单元未使用*/ for(i=1; i<=n; i++) ht[i] ={ w[i], 0, 0, 0}; /*叶子结点初始化*/ for(i=n+1; i<=m; i++) ht[i] ={0, 0, 0, 0}; /*非叶子结点初始化*/
ht[i].weight=ht[s1].weight+ht[s2].weight; } /*哈夫曼树建立完毕*/
第十七讲
/*从叶子结点到根, 逆向求每个叶子结点对应的哈夫曼编码*/ hcode=(HuffmanCode)malloc((n+1)*sizeof(char *)); /*分配n个编码的头指针*/ cd=(char * )malloc(n * sizeof(char )); /*分配求当前编码的工作空间*/ cd[n-1]=′\0′; /*从右向左逐位存放编码, 首先存放编码结束符*/ for(i=1; i<=n; i++) /*求n个叶子结点对应的哈夫曼编码*/ { start=n-1; /*初始化编码起始指针*/ for(c=i, p=ht[i].parent; p! =0; c=p, p=ht[p].parent) if(ht[p].LChild==c) cd[--start]=′0′; /*左分支标0*/ else cd[--start]=′1′; /*右分支标1*/ hcode[i]=(char *)malloc((n-start)*sizeof(char)); /*为第i个编码分配空间*/ strcpy(hcode[i], &cd[start]); } free(cd); }
第十七讲
2 C 4 7 A 5 B 2 C 4 D D 7 A 5 B
7 A 5 B 2 C 4 D
(a) 带权路径长度为 36
(b) 带权路径长度为 46
(c) 带权路径长度为 35
WPL(a)=7×2+5×2+2×2+4×2=36 WPL(b)=4×2+7×3+5×3+2×1=46 WPL(c)=7×1+5×2+2×3+4×3=35
第十七讲
(3) 从F中删除被选中的那两棵二叉树, 同时把新构 成的二叉树加入到森林F中。 (4) 重复(2)、(3)操作, 直到森林中只含有一棵 二叉树为止, 此时得到的这棵二叉树就是哈夫曼树。
第十七讲
6.5.2 哈夫曼编码
表 6 – 1 指令的使用频率
指令 I1 I2 I3 I4 I5 I6 I7 使用频率(Pi) 0.40 0.30 0.15 0.05 0.04 0.03 0.03
7 4 3 2
(c) WPL=1×7+2×4+3×3+3×2=7+8+9+6=30
第十七讲
4. 哈夫曼树 构造哈夫曼算法的步骤如下: (1) 用给定的n个权值{w1, w2, …, wn}对应的n个结点构成n 棵二叉树的森林F={T1, T2, …, Tn},其中每一棵二叉树T i(1≤i≤n)都只有一个权值为wi的根结点,其左、右子树为空。 (2) 在森林F中选择两棵根结点权值最小的二叉树,作为 一棵新二叉树的左、右子树,标记新二叉树的根结点权值为其 左右子树的根结点权值之和。
第十七讲
树与森林的遍历
第十七讲
1. 树的遍历 树的遍历 树的遍历方法主要有以下两种: 1) 先根遍历 若树非空,则遍历方法为: (1) 访问根结点。 (2) 从左到右, 依次先根遍历根结点的每一棵子树。 例如, 图6.21中树的先根遍历序列为ABECFHGD。
第十七讲
2) 后根遍历 若树非空, 则遍历方法为: (1) 从左到右, 依次后根遍历根结点的每一棵子树。 (2) 访问根结点。 2 例如, 图6.21中树的后根遍历序列为EBHFGCDA。
第十七讲
问题2: 问题 什么样的树的带权路径长度最小? 例如: 给定一个权值序列{2, 3, 4, 7}, 可构造如图6.29所 示的多种二叉树的形态。
第十七讲
2 3 2 3 4 7 4 7
(a) WPL=2×2+2×3+2×4+2×7=32
(b) WPL=1×2+2×3+3×4+3×7=41
第十七讲
问题1: 什么样的二叉树的路径长度PL最小? 路径长度为0的结点至多只有1个(根); 路径长度为1的结点至多只有2个; 路径长度为2的结点至多只有4个; 依此类推,路径长度为k的结点至多只有2k个, 所以n个结 点二叉树其路径长度至少等于如下所示序列的前n项之和。
结点路径长度0,1, 1, 2,2,2,2, 3, 3, 3, 3, 3, 3, 3, 3, 4,… 结点数n n=1 n=2 n=3 n=4 n=5 n=6 n=7 n=8 … n=15
第十七讲
2) 中序遍历 若森林非空, 则遍历方法为: (1) 中序遍历森林中第一棵树的根结点的子树森林。 (2) 访问第一棵树的根结点。 (3) 中序遍历除去第一棵树之后剩余的树构成的森林。 例如, 图6.24(a)中森林的中序遍历序列为 BCDAFEHJIG。
第十七讲
3) 后序遍历 若森林非空, 则遍历方法为: (1) 后序遍历森林中第一棵树的根结点的子树森林。 (2) 后序遍历除去第一棵树之后剩余的树构成的森林。 (3) 访问第一棵树的根结点。
按规定:0左1右, 则有 000 2 c 001 3 s 01 5 e 10 7 a 11 8 t
第十七讲
所 以 有 state 的 编 码 为 00111101101, stat 的 编 码 为 001111011。 构造满足哈夫曼编码的最短最优性质: (1) 若di≠dj(字母不同),则对应的树叶不同。 因此前 缀码(任一字符的编码都不是另一个字符编码)不同,一 个路径不可能是其它路径的一部分, 所以字母之间可以完 全区别。
第十七讲
6.5.3 哈夫曼编码算法的实现
由于哈夫曼树中没有度为1的结点,则一棵有n个叶子的哈 夫曼树共有2×n-1个结点,可以用一个大小为2×n-1 的一维 数组存放哈夫曼树的各个结点。 由于每个结点同时还包含其 双亲信息和孩子结点的信息,所以构成一个静态三叉链表。 静态三叉链表描述如下:
typedef struct { unsigned int weight ; /* 用来存放各个结点的权值*/ unsigned int parent, LChild, RChild ; /*指向双亲、 孩子结点的指针*/ }HTNode, * HuffmanTree; /*动态分配数组, 存储哈夫曼树*/ typedef char * *HuffmanCode ; /*动态分配数组, 存储哈夫曼编码*/
相关主题