1 / 28

第 6 章 树和二叉树( Tree & Binary Tree )

第 6 章 树和二叉树( Tree & Binary Tree ). 6.1 树的基本概念 6.2 二叉树 6.3 遍历二叉树和线索二叉树 6.4 树和森林 6.5 赫夫曼树及其应用. n+1. 问: 用二叉链表法( l_child, r_child )存储包含 n 个结点的二叉树,结点的指针区域中必有 个空指针。. 分析: ① n 个结点必有 2n 个链域; (见二叉链表数据类型说明) ②除根结点外,二叉树中每一个结点 有且仅有一个双亲 (直接前驱),所以只会有 n - 1 个结点的链域存放指针,指向非空子女结点(即直接后继)。.

Download Presentation

第 6 章 树和二叉树( Tree & Binary Tree )

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第6章 树和二叉树( Tree & Binary Tree ) 6.1 树的基本概念 6.2 二叉树 6.3 遍历二叉树和线索二叉树 6.4 树和森林 6.5 赫夫曼树及其应用

  2. n+1 问:用二叉链表法(l_child, r_child)存储包含n个结点的二叉树,结点的指针区域中必有个空指针。 分析: ①n个结点必有2n个链域; (见二叉链表数据类型说明) ②除根结点外,二叉树中每一个结点有且仅有一个双亲(直接前驱),所以只会有n-1个结点的链域存放指针,指向非空子女结点(即直接后继)。 所以, 空指针个数=2n-(n-1)=n+1个。 思考:二叉链表空间效率这么低,能否利用这些空闲区存放有用的信息或线索?

  3. 增加两个域:fwd和bwd; 两种解决方法: 二、线索二叉树(Threaded Binary Tree) 1. 定义 2. 生成 3. 遍历 普通二叉树只能找到结点的左右孩子信息,而该结点的直接前驱和直接后继只能在遍历过程中获得。 若将遍历后对应的有关前驱和后继预存起来,则从第一个结点开始就能很快“顺藤摸瓜”而遍历整个树了。 例如中序遍历结果:B D C E A F H G,实际上已将二叉树转为线性排列,显然具有唯一前驱和唯一后继。 如何预存这类信息? 存放前驱指针 存放后继指针 利用空链域(n+1个空链域)

  4. 规定: 1)若结点有左子树,则lchild指向其左孩子; 否则, lchild指向其直接前驱(即线索); 2)若结点有右子树,则rchild指向其右孩子; 否则, rchild指向其直接后继(即线索)。 LTag RTag 左孩子或前驱 右孩子或后继 为区别两种不同情况,特增加两个标志域(各1bit) 约定: 当Tag域为0时,表示正常情况; 当Tag域为1时,表示线索情况.

  5. 附:有关线索二叉树的几个术语: 线索链表:用含Tag的结点样式所构成的二叉链表 线 索:指向结点前驱和后继的指针 线索二叉树:加上线索的二叉树 线 索 化:对二叉树以某种次序遍历使其变为线索二叉树的过程 讨论:增加了前驱和后继等线索有什么好处? ——能方便找出当前结点的前驱和后继,不用堆栈也能遍历整个树。

  6. 例:某先序遍历结果如下表所示,请画出对应的二叉树。例:某先序遍历结果如下表所示,请画出对应的二叉树。 (多带了两个标志!) A G H E D C F J I B

  7. 2. 线索二叉树的生成 线索化过程就是在遍历过程中修改空指针的过程: 将空的lchild改为结点的直接前驱; 将空的rchild改为结点的直接后继。 非空指针呢?仍然指向孩子结点(称为“正常情况”)

  8. A root C B G F E D I H 例1:画出以下二叉树对应的中序线索二叉树。 解:该二叉树中序遍历结果为:H, D, I, B, E, A, F, C, G 所以添加线索应当按如下路径进行: 悬空? 为避免悬空态,应增设一个头结点 悬空?

  9. 对应的中序线索二叉树存储结构如图所示: root -- 0 0 A 0 0 C B 0 0 0 0 1 G F E 1 D 1 1 1 0 1 0 H 1 1 I 1 1 注:此图中序遍历结果为: H, D, I, B, E, A, F, C, G

  10. 28 25 33 NIL NIL 40 60 08 54 55 例2:【 2000年计算机系考研题】给定如图所示二叉树T,请画出与其对应的中序线索二叉树。 解:因为中序遍历序列是:55 40 25 60 28 08 33 54 对应线索树应当按此规律连线,即在原二叉树中添加虚线。

  11. 线索二叉树的生成算法(算法6.6, 见教材P134) 目的:在依某种顺序遍历二叉树时修改空指针,添加前驱或后继。 注解:为方便添加结点的前驱或后继,需要设置两个指针: p指针→当前结点之指针; pre指针→前驱结点之指针。 技巧:当结点p的左/右域为空时,只改写它的左域(装入前驱pre),而其右域(后继)留给下一结点来填写。 或者说,当前结点的指针p应当送到前驱结点的空右域中。 若p->lchild=NULL,则{p->Ltag=1;p->lchild=pre;} //p的前驱结点指针pre存入左空域 若pre->rchild=NULL, 则{pre->Rtag=1;pre->rchild=p;} //p存入其前驱结点pre的右空域

  12. ② ③ ④ ⑤ ⑦ ⑥ ⑧ ⑨ ⑩…… 3. 线索二叉树的遍历 理论上,只要找到序列中的第一个结点,然后依次访问结点的后继直到后继为空时结束。 但是,在线索化二叉树中,并不是每个结点都能直接找到其后继的,当标志为0时,R_child=右孩子地址指针,并非后继!需要通过一定运算才能找到它的后继。 以中序线索二叉树为例: 对叶子结点(RTag=1),直接后继指针就在其rchild域内; 对其他结点(RTag=0),直接后继是其右子树最左下的结点; (因为中序遍历规则是LDR,先左再根再右)

  13. 线索二叉树的中序遍历算法(算法6.5, 参见教材P134) 程序注解 (非递归,且不用栈): P=T->lchild; //从头结点进入到根结点; while( p!=T) {while(p->LTag==link)p=p->lchild; //先找到中序遍历起点 if(!visit(p->data)) return ERROR; //若起点值为空则出错告警 while(p->RTag==Thread ……){ p=p->rchild; Visit(p->data);} //若有后继标志,则直接提取p->rchild中线索并访问后继结点; p=p->rchild; //当前结点右域不空或已经找好了后继,则一律从结点的右子树开始重复{ }的全部过程。 } Return OK; LTag=0 RTag=1

  14. p=T->lchild; N p!=T Y N p->LTag==0 return OK; Y p=p->lchild; vist(p->data); N p->LTag==1&&p->rchild!=T Y p=p->rchild;visit(p->data); p=p->rchild; 算法流程: 演 示 程 序

  15. 提前介绍:二叉树的应用 平衡树—— 排序树—— 字典树—— 判定树—— 带权树—— 最优树—— 特点:左右子树深度差 ≤1 特点:“左小右大”(见实验二的方案1) 由字符串构成的二叉树排序树 例如,12个球只称3次分出轻重 特点:路径长度带权值 带权路径长度最短的树,又称 Huffman树,用途之一是通信中的压缩编码。

  16. a c b g f e d 6.5 Huffman树及其应用 一、最优二叉树(霍夫曼树) 预备知识:若干术语 路 径: 路径长度: 树的路径长度: 带权路径长度: 树的带权路径长度: 霍 夫 曼 树: 由一结点到另一结点间的分支所构成 路径上的分支数目 a→e的路径长度= 2 从树根到每一结点的路径长度之和。 树长度= 10 结点到根的路径长度与结点上权的乘积 树中所有叶子结点的带权路径长度之和 带权路径长度最小的树。

  17. Weighted Path Length n WPL = wklk k=1 7 2 c a 5 4 2 4 7 5 b c d d b a 2 4 5 7 (a) b c d a (b) (c) Huffman树简介: 树的带权路径长度如何计算? 哈夫曼树则是:WPL 最小的树。 经典之例: Huffman树 WPL= 35 WPL=36 WPL=46

  18. 构造霍夫曼树的基本思想: 权值大的结点用短路径,权值小的结点用长路径。 构造Huffman树的步骤(即Huffman算法): (1)由给定的 n 个权值{w0, w1, w2, …, wn-1},构造具有 n 棵扩充二叉树的森林F = { T0, T1, T2, …, Tn-1 },其中每一棵扩充二叉树 Ti 只有一个带有权值 wi 的根结点,其左、右子树均为空。 (2)重复以下步骤, 直到 F 中仅剩下一棵树为止: ① 在 F 中选取两棵根结点的权值最小的扩充二叉树, 做为左、右子树构造一棵新的二叉树。置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。 ② 在 F 中删去这两棵二叉树。 ③ 把新的二叉树加入 F。

  19. 例1:设有4个字符d,i,a,n,出现的频度分别为7,5,2, 4,怎样编码才能使它们组成的报文在网络中传得最快? 法1:等长编码。例如用二进制编码来实现。 取 d=00,i=01,a=10,n=11 法2:不等长编码,例如用哈夫曼编码来实现。 取 d=0; i=10, a=110, n=111 最快的编码是哪个? 是非等长的Huffman码! 怎样实现Huffman编码? 先要构造Huffman树!

  20. 构造Huffman树的步骤: 操作要点1:对权值的合并、删除与替换 ——在权值集合{7,5,2,4}中,总是合并当前值最小的两个权 注:方框表示外结点(叶子,字符对应的权值), 圆框表示内结点(合并后的权值)。

  21. 0 1 d 0 1 i 1 0 a n 操作要点2:按左0右1对Huffman树的所有分支编号! ——将 Huffman树 与 Huffman编码 挂钩 Huffman编码结果:d=0, i=10, a=110, n=111 WPL=1bit×7+2bit×5+3bit(2+4)=35 特点:每一码都不是另一码的前缀,绝不会错译! 称为前缀码

  22. 霍夫曼编码的基本思想是:概率大的字符用短码,概率小的用长码。由于霍夫曼树的WPL最小,说明编码所需要的比特数最少。这种编码已广泛应用于网络通信中。霍夫曼编码的基本思想是:概率大的字符用短码,概率小的用长码。由于霍夫曼树的WPL最小,说明编码所需要的比特数最少。这种编码已广泛应用于网络通信中。 例2(严题集6.26③):假设用于通信的电文仅由8个字母 {a, b, c, d, e, f, g, h} 构成,它们在电文中出现的概率分别为{ 0.07, 0.19, 0.02, 0.06, 0.32, 0.03, 0.21, 0.10},试为这8个字母设计哈夫曼编码。如果用0~7的二进制编码方案又如何? 解:先将概率放大100倍,以方便构造哈夫曼树。权值集合 w={7, 19, 2, 6, 32, 3, 21, 10}, 按哈夫曼树构造规则(合并、删除、替换),可得到哈夫曼树。

  23. × × × × 100 × × × × 60 × × 32 × × 40 × × 19 21 g e b 2 3 7 10 a d h f c 为清晰起见,重新排序为:w={2, 3, 6, 7, 10, 19, 21, 32} w1={5, 6, 7, 10, 19, 21, 32} w2={7, 10, 11, 19, 21, 32} w3={11, 17, 19, 21, 32} w4={19, 21, 28, 32} 28 w5={28,32,40} w6={40,60} 17 11 w7={100} 6 5 哈夫曼树

  24. 100 60 1 0 28 32 0 0 1 1 17 11 40 0 1 6 5 0 1 0 1 19 21 g e b 1 0 2 3 7 10 a d h f c 对应的哈夫曼编码(左0右1): Huffman码的WPL=2(0.19+0.32+0.21) + 4(0.07+0.06+0.10) +5(0.02+0.03) =1.44+0.92+0.25=2.61 WPL=3(0.19+0.32+0.21+0.07+0.06+0.10+0.02+0.03)=3 二进制码

  25. 另一种结果表示:

  26. 字符 空格 a b c d e f g h i 频度 186 64 13 22 32 103 21 15 47 57 字符 j k l m n o p q r s 频度 1 5 32 20 57 63 15 1 48 51 字符 t u v w y z x 频度 80 23 8 18 1 16 1 例3(实验二方案3):设字符集为26个英文字母,其出现频度如下表所示。 要求编程实现: 先建哈夫曼树,再利用此树对报文“This program is my favorite”进行编码和译码。

  27. 提示1:霍夫曼树中各结点的结构可以定义为如下5个分量:提示1:霍夫曼树中各结点的结构可以定义为如下5个分量: 提示2:霍夫曼树的存储结构可采用顺序存储结构: 将整个霍夫曼树的结点存储在一个数组中:HT[1..n]; 将结点的编码存储在HC[1..n]中。 提示3:霍夫曼树如何构造?构造好之后又如何求得各结点对应的霍夫曼编码?——算法参见教材P147。

  28. 顺序结构 二叉链表 链式结构 二叉树 三叉链表 森林 先序遍历 中序遍历 后序遍历 先序线索树 中序线索树 后序线索树 霍夫曼树 二叉树小结 1、定义和性质 2、存储结构 3、遍历 4、线索化:线索树 霍夫曼编码

More Related