1 / 81

6.4 树和森林 ( 知识点三 )

6.4 树和森林 ( 知识点三 ). 6.4.1 树的存储结构. 6.4.2 树与二叉树的转换. 6.4.3 树和森林的遍历. 6.4.1 树的存储结构 -1. 树存储结构分三种 ——. ( 一 ) 树的双亲表示法. ( 二 ) 树的孩子链表表示法. ( 三 ) 树的孩子兄弟表示法 (又称 二叉树或二叉链表表示法 ). 6.4.1 树的存储结构 -2. ( 一 ) 树的双亲表示法 -1. root=0. n=6. data parent. 0 A -1 1 B 0 2 C 0 3 D 0 4 E 2

Download Presentation

6.4 树和森林 ( 知识点三 )

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.4 树和森林(知识点三)

  2. 6.4.1 树的存储结构 6.4.2 树与二叉树的转换 6.4.3 树和森林的遍历

  3. 6.4.1 树的存储结构-1 树存储结构分三种—— (一) 树的双亲表示法 (二)树的孩子链表表示法 (三) 树的孩子兄弟表示法 (又称二叉树或二叉链表表示法)

  4. 6.4.1 树的存储结构-2 (一 ) 树的双亲表示法-1 root=0 n=6 data parent 0A-1 1B0 2 C 0 3D 0 4E2 5F2 6G5 A B C D E F G

  5. (一 ) 树的双亲表示法-2 C语言的类型描述树的双亲表示法: #define MAX_TREE_SIZE 100 结点结构: data parent typedef struct PTNode { Elem data; intparent; // 双亲位置域 } PTNode;

  6. (一 ) 树的双亲表示法-3 树结构: typedef struct { PTNode nodes [MAX_TREE_SIZE]; int r, n; // 根结点的位置和结点个数 } PTree;

  7. (二) 树的孩子链表表示法-1 root=0 n=6 data firstchild A 0 A -1 1 B 0 2 C 0 3 D 0 4 E 2 5 F 2 6 G 5 1 2 3 B C D 4 5 E F 6 G

  8. (二) 树的孩子链表表示法-2 C语言的类型描述树的孩子链表表示: 孩子结点结构: child next typedef struct CTNode { int child; struct CTNode *next; } *ChildPtr;

  9. data firstchild 双亲结点结构 typedef struct { Elem data; ChildPtr firstchild; // 孩子链的头指针 } CTBox;

  10. 树结构: typedef struct { CTBox nodes[MAX_TREE_SIZE]; int n, r; // 结点数和根结点的位置 } CTree;

  11. (三) 树的孩子兄弟表示法 (又称二叉树或二叉链表表示法) root A B C E D F G root A root A B C E D GF B C D E F G

  12. C语言的类型描述: 结点结构: firstchild data nextsibling typedef struct CSNode{ Elem data; struct CSNode *firstchild, *nextsibling; } CSNode, *CSTree;

  13. 树的孩子兄弟表示法 root=0 n=6 A 1 2 3 0 1 2 3 4 5 6 B C D 4 5 E F 6 G

  14. 6.4.2 树与二叉树的转换 (一)森林和二叉树的对应关系 假设:森林有如下棵树组成,即 F = ( T1, T2, …, Tn ); T1 = (root,t11, t12, …, t1m); 二叉树 B =( LBT, Node(root), RBT );

  15. 由森林转换成二叉树的转换规则为: 若 F = Φ,则 B = Φ; 否则, 由 ROOT( T1 )对应得到 Node(root); 由 (t11, t12, …, t1m )对应得到 LBT; 由 (T2, T3,…, Tn )对应得到 RBT。

  16. 由二叉树转换为森林的转换规则为: 若 B = Φ, 则 F = Φ; 否则, 由 Node(root)对应得到 ROOT( T1); 由LBT对应得到 ( t11, t12, …,t1m); 由RBT对应得到 (T2, T3, …, Tn)。

  17. 由此,树的各种操作均可对应二叉树的操作来完成。由此,树的各种操作均可对应二叉树的操作来完成。 应当注意的是,和树对应的二叉树,其左、右子树的概念 已改变为:左是孩子,右是兄弟。

  18. 6.4.3 树和森林的遍历

  19. (一) 树的遍历 (二) 森林的遍历 (三) 树的遍历的应用

  20. 树的遍历可有三条搜索路径: 先根(次序)遍历: 若树不空,则先访问根结点,然后依次先根遍历各棵子树。 后根(次序)遍历: 若树不空,则先依次后根遍历各棵子树,然后访问根结点。 按层次遍历: 若树不空,则自上而下自左至右访问树中每个结点。

  21. 先根遍历时顶点的访问次序: A E F G I J K B C A B E F C D G H I J K D 后根遍历时顶点的访问次序: E F B C I J K H G D A H 层次遍历时顶点的访问次序: A B C D E F G H I J K

  22. E F G H 森林由三部分构成: 1.森林中第一棵树的根结点; B C D 2.森林中第一棵树的子树森林; 3.森林中其它树构成的森林。 I J K

  23. 森林的遍历 若森林不空,则 访问森林中第一棵树的根结点; 先序遍历森林中第一棵树的子树森林; 先序遍历森林中(除第一棵树之外)其 余树构成的森林。 1. 先序遍历 即:依次从左至右对森林中的每一棵树进行先根遍历。

  24. 2.中序遍历 若森林不空,则 中序遍历森林中第一棵树的子树森林; 访问森林中第一棵树的根结点; 中序遍历森林中(除第一棵树之外)其 余树构成的森林。 即:依次从左至右对森林中的每一棵树进行后根遍历。

  25. 树的遍历和二叉树遍历的对应关系 ? 树 森林 二叉树 先根遍历 先序遍历 先序遍历 中序遍历 中序遍历 后根遍历

  26. 设树的存储结构为孩子兄弟链表 typedef struct CSNode{ Elem data; struct CSNode *firstchild, *nextsibling; } CSNode, *CSTree; 一、求树的深度 二、输出树中所有从根到叶子的路径 三、建树的存储结构

  27. 一、求树的深度的算法: int TreeDepth(CSTree T) { if(!T) return 0; else { h1 = TreeDepth( T->firstchild ); h2 = TreeDepth( T->nextsibling); } } // TreeDepth return(max(h1+1, h2));

  28. 二、输出树中所有从根到叶子的路径的算法: 例如:对左图所示的树,其输出结果应为: A B C D E F G H I J K A B E A B F A C A D G H I A D G H J A D G H K

  29. void AllPath( Bitree T, Stack& S ) { if (T){ Push( S, T->data ); if (!T->Lchild && !T->Rchild ) PrintStack(S); else {AllPath( T->Lchild, S ); AllPath( T->Rchild, S ); } Pop(S); } //if(T) } // AllPath // 输出二叉树上从根到所有叶子结点的路径

  30. void OutPath( Bitree T, Stack& S ) { while ( !T ) { Push(S, T->data ); if ( !T->firstchild ) Printstack(s); else OutPath( T->firstchild, s ); Pop(S); T = T->nextsibling; } // while } // OutPath // 输出森林中所有从根到叶的路径

  31. 三、建树的存储结构的算法: 和二叉树类似,不同的定义相应有不同的算法。 假设以二元组(F,C)的形式自上而下、自左而右依次输入树的各边,建立树的孩子-兄弟链表。

  32. 例如: 对下列所示树的输入序列应为: (‘#’, ‘A’) (‘A’, ‘B’) (‘A’, ‘C’) (‘A’, ‘D’) (‘C’, ‘E’) (‘C’, ‘F’) (‘E’, ‘G’) A A (‘#’, ‘A’) (‘A’, ‘B’) B B C D (‘A’, ‘C’) C E F (‘A’, ‘D’) D (‘C’, ‘E’) G 可见,算法中需要一个队列保存已建好的结点的指针。

  33. void CreatTree( CSTree &T ) { T = NULL; for( scanf(&fa, &ch); ch!=; scanf(&fa, &ch);) { p = GetTreeNode(ch); // 创建结点 EnQueue(Q, p); // 指针入队列 if (fa ==) T = p; // 所建为根结点 else {} // 非根结点的情况 } // for } // CreateTree … …

  34. GetHead(Q,s); // 取队列头元素(指针值) while (s->data != fa ) { // 查询双亲结点 DeQueue(Q,s); GetHead(Q,s); } if (!(s->firstchild)) { s->firstchild = p; r = p; } // 链接第一个孩子结点 else{ r->nextsibling = p; r = p; } // 链接其它孩子结点

  35. 6.6 哈夫曼树及其应用 哈夫曼树又称最优二叉树,它是一种带权路径长度最短的树,具有广泛的应用。 6.6.1 最优二叉树(哈夫曼树) 6.6.2哈夫曼编码

  36. 6.6.1 最优二叉树(哈夫曼树) 根据最优二叉树( Huffman哈夫曼树)是一种带权路径长度最短的树的特征,我们分别给出树的结点的路径长度、树的路径长度、树的带权路径长度及最优二叉树的定义。 定义一:结点的路径长度 从树的根结点到该结点的路径上分支的数目。 定义二:树的路径长度 树中每个结点的路径长度之和。

  37. 定义三:树的带权路径长度(Weight Path Length,WPL) 树中所有叶子结点的带权路径长度之和 WPL =  wklk (对所有叶子结点)。 K=1 n 定义四:最优二叉树(哈夫曼树) 假设有n个权值{w1,w2,…,wn},试构造一棵n个叶子结点的二叉树,每个叶子结点带权为wi,则带权路径长度WPL最小的二叉树称为最优二叉树(哈夫曼树)。

  38. 7 2 a 5 c b 4 a 2 c d b 4 d d c 5 7 (c) a b 构造最优二叉树(哈夫曼树)举例1: (1)在所有含 n 个叶子结点、并带相同权值的 m 叉树中,必存在一棵其带权路径长度取最小值的树,称为“最优树”。 (a)WPL=7*2+5*2+2*2+4*2=36 (b)WPL=4*2+7*3+5*3+2*1=46 (c)WPL=7*1+5*2+2*3+4*3=35,该树的WPL最小,所以为哈夫曼树。 4 5 2 7 (a) (b) P144 图6.22

  39. 二、如何构造最优树 (哈夫曼树即赫夫曼算法) 以二叉树为例: (1) 根据给定的 n 个权值 {w1, w2, …, wn}, 构造 n 棵二叉树的集合 F = {T1, T2, … , Tn}, 其中每棵二叉树中均只含一个带权值为 wi 的根结点,其左、右子树为空树;

  40. (2) 在 F 中选取其根结点的权值为最小的两棵二叉树,分别作为左、 右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之 和;

  41. (3) 从F中删去这两棵树,同时加入刚生成的新树; (4)重复(2)和(3)两步,直至 F 中只含一棵树为止。

  42. 构造哈夫曼树举例 例:一组字符{A, B, C, D, E, F, G}出现的频率分别是{9, 11, 5, 7, 8, 2, 3},构造哈夫曼树。 (1) 根据给定的 7个权值 {9,11,5,7,8,2,3}, 构造 7 棵二叉树的集合 F F = {T1, T2, … , Tn } ={ , , , , , , }, 其中每棵二叉树中均只含一个带权值为 wi 的根结点,其左、右子树为空树; 5 7 8 2 3 9 11

  43. (2)在 F 中选取其根结点的权值为最小的两棵二叉树,分别作为左、 右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和; 5 5 2 2 3 3 (3) 从F中删去这两棵树,同时加入刚生成的新树; F={ , , , , , } 5 7 9 11 8

  44. 10 10 5 5 5 5 2 2 3 3 重复(2)和(3)两步 (2)再在F 中选取其根结点的权值为最小的两棵二叉树,分别作为左、右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和; (3) 再从F中删去这两棵树,同时加入刚生成的新树; F={ , , , , } 7 8 9 11

  45. 15 15 10 7 7 8 8 5 5 2 3 重复(2)和(3)两步 (2)再在F 中选取其根结点的权值为最小的两棵二叉树,分别作为左、右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和; 7 8 (3) 再从F中删去 这两棵树,同时加入刚生成的新树; F={ , , , } 9 11

  46. 重复(2)和(3)两步 19 15 15 9 10 7 7 8 8 5 5 2 3 (2)再在F 中选取其根结点的权值为最小的两棵二叉树,分别作为左、右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和; 10 9 (3) 再从F中删去 这两棵树,同时加入刚生成的新树; F={ , , } 11

  47. 重复(2)和(3)两步 19 19 15 9 9 10 10 7 8 5 5 5 5 2 2 3 3 (2)再在F 中选取其根结点的权值为最小的两棵二叉树,分别作为左、右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和; 9 10 (3) 再从F中删去 这两棵树,同时加入刚生成的新树; F={ , , } 11

  48. 重复(2)和(3)两步 19 26 26 9 11 11 15 15 10 5 5 7 7 8 8 2 3 (2)再在F 中选取其根结点的权值为最小的两棵二叉树,分别作为左、右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和; 15 (3) 再从F中删去 这两棵树,同时加入刚生成的新树; 11 F={ , }

  49. 再重复(2)和(3)两步 45 10 9 11 15 26 19 5 5 7 8 2 3 (2)再在F 中选取其根结点的权值为最小的两棵二叉树,分别作为左、右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和; (3) 再从F中删去 这两棵 树,同时加入刚 生成的新树; 19 26 A B C E D F G

  50. 45 10 9 A 11 15 B 26 19 5 5 7 8 C D E 2 3 F G (3) 再从F中删去 这两棵树,同时加入刚生成的新树; 26 19 F={ } 这时,F中仅含有一棵树,因此,该树为最优二叉树即哈夫曼树。

More Related