1 / 18

数据结构

数据结构. 第六章 树与森. §6.6 树与森林. firstchild. data. NextSibling. root. A. B. G. A. I. C. D. ∧. ∧. ∧. B. C. D. ∧. E. E. F. G. H. I. J. ∧. F. ∧. K. L. M. ∧. K. ∧. H. ∧. L. ∧. ∧. M. ∧. ∧. J. ∧. 一、树的第一个孩子和下一个兄弟存贮表示. 1 、结点结构. 2 、存贮示例.

Download Presentation

数据结构

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. 数据结构 第六章 树与森

  2. §6.6 树与森林 firstchild data NextSibling root A B G A I C D ∧ ∧ ∧ B C D ∧ E E F G H I J ∧ F ∧ K L M ∧ K ∧ H ∧ L ∧ ∧ M ∧ ∧ J ∧ 一、树的第一个孩子和下一个兄弟存贮表示 1、结点结构 2、存贮示例 ☆因每个结点有且仅有两个指针域,所以也称为二叉链或二叉树表示方法

  3. 3、类声明 template <class Type> class Tree; template <class Type> class TreeNode{ friend class <Type> Tree; private: Type data; TreeNode <Type> * firstchild, * nextSibling; TreeNode (Type value = 0, TreeNode<Type> *fc = NULL, TreeNode<Type> *ns = NULL) : data (value), firstChild (fc), nextSibling (ns) { }} template <class Type> class Tree { private: TreeNode <Type> * root, * current; …… public: Tree ( ) {root = current = NULL;} void PreOrder ( ); //先根遍历树 void PostOrder ( ); //后根遍历树 void LevelOrder ( ); //广度优先遍历树 int IsEmpty ( ) {return root = = NULL; } ……}

  4. root A B C E D F G H K I L J M 二、树的遍历(二叉链存贮下) 1、深度优先遍历 ▲先根遍历 ☆先根遍历的顺序 访问树的根结点 先根遍历第一棵子树,第二棵子树等 ☆对上例给定树的树先根遍历输出序列: A B E F C G K L D H I M J

  5. 1、深度优先遍历 ☆先序遍历算法 template <class Type> void Tree<Type> :: PreOrder ( ){ if (! IsEmpty ( )) { //对以current为根的树先序遍历 cout <<current -> data << " "; TreeNode <Type> * p = current; current = current -> firstchild; //找根的第一棵子树 while (current != NULL) { //先序遍历所有子树 PreOrder( ); current = current -> nextSibling;} current = p; } } ☆先序遍历结果与对应二叉树的先序遍历结果相同

  6. root A B C E D F G H K I L J M 1、深度优先遍历 ▲后根遍历 ☆后根遍历的顺序 按后根遍历第一棵子树,第二棵子树等 访问树的根结点 ☆对上例给定树的树后根遍历输出序列: E F B K L G C H M I J D A

  7. 1、深度优先遍历 ☆后序遍历算法 template <class Type> void Tree<Type> :: PostOrder ( ){ if (! IsEmpty ( )) { //对以current为根的树后序遍历 TreeNode <Type> * p = current; current = current -> firstchild; //找第一棵子树 while (current != NULL) { PostOrder( ); current = current -> nextSibling;} current = p; cout <<p -> data << " "; } } ☆后序遍历结果与对应二叉树的中序遍历结果相同

  8. 第0层 A 第1层 A B 第2层 B C D E 第3层 C F D E F G H I J G K H K L M L I M J 2、广度优先遍历 ▲广度优先即层次优先,同层中先左后右 ▲示例 输出序列:A B C D E F G H I J K L M

  9. 2、广度优先遍历 ▲广度优先遍历算法 template <class Type> void Tree<Type> :: LevelOrder ( ){ Queue <TreeNode <Type> *> Qu; TreeNode <Type> *p; if (current != NULL) { p = current; Qu.EnQueue (current); while (! Qu.IsEmpty ( )) { current = Qu.GetFront ( ); Qu.DeQueue ( ); cout << current -> data <<" "; current = current -> firstchild; while (current != NULL) { Qu.EnQueue (current); current = current -> nextSibling; }} current = p; }}

  10. T1 T2 T3 A H F T1 T2 T3 A H F B I G B C D G I J J C E K E K D (a)3棵树的森林 A (b) 树的二叉树表示 T1 B F T2 E C G H T3 D I J (c) 森林的二叉树表示 K 三、森林与二叉树的转换 1、森林是树的有限集合 2、若将每棵树分别用二叉树表示,然后通过下一个兄弟域顺序链接在一起,就得到了森林的二叉树表示 3、森林与二叉树互换的示例   

  11. 0 0 1 1 2 2 3 3 4 5 6 4 7 5 6 7 (a) PL = 13 (b) PL = 15 §6.7 霍夫曼树 一、树的路径长度(PL) 1、PL是指从根到其它各结点的路径长度(分支数)之和

  12. 一、树的路径长度(PL) 2、具有n个结点的路径长度分析 完全二叉树各结点的路径长度分别是数列 0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4, …的前n项之和,具有最小值 若n个结点的高度为h的二叉树,从根到 h – 1 层都有最多结点数 2h – 1 ,其余结点分布在第 h 层的任意位置上,也具有最小 PL ,这种树称为理想平衡二叉树。

  13. 带权的叶子结点又名外结点,具有外结点的树叫扩充二叉树 具有n个外结点,其中任意结点的权值为Wi,到根的路径长度为 li,则该扩充二叉树的带权路径长度为: 具有最小 WPL 的扩充二叉树叫霍夫曼树 2 7 4 5 2 4 5 7 7 4 5 2 (a) WPL = 36 (b) WPL = 46 (c) WPL = 35 (霍夫曼树) 二、霍夫曼树 1、树的带权(Weighted)路径长度 WPL

  14. 18 11 11 7 6 5 6 , , , , , , 7 5 7 6 7 2 5 4 5 2 4 2 4 (a) 2 4 (b) (c) (d) 二、霍夫曼树 2、霍夫曼树的构造方法 将n个权值视为具有n棵扩充二叉树的森林F,然后重复以下步骤,直到F中只有一棵树为止: ①在F中选根的权值最小的两棵作为左右子树构造一棵新的二叉树,其根的权为左右子树根的权值之和。 ②在F中删除那两棵树,并把新的二叉树加入。

  15. 二、霍夫曼树 3、扩充二叉树类的声明 const int DefaultSize = 20; template <class Type> class ExtBinTree; template <class Type> class Element { friend class ExtBinTree; private : Type data; Element <Type >* leftchild, * rightchild;} template <class Type> class ExtBinTree { private : Element <Type> * root; public : ExtBinTree (ExtBinTree <Type> & bt1, ExtBinTree <Type> & bt2) { //构造新二叉树 root -> leftchild = bt1.root; root -> rightchild = bt2.root; root -> data.key = bt1.root -> data.key + bt2.root -> data.key; }}

  16. 二、霍夫曼树 4、构造霍夫曼树的算法 template <class Type> void HuffmanTree (Type *fr, int n, ExtBinTree <Type> & newtree) { //以权值fr[0]~fr[n-1]构造霍树 ExtBinTree <Type> first, second; ExtBinTree <Type> Node[DefaultSize]; //n棵树组成的森林 MinHeap <ExtBinTree <Type>> hp; //算法中使用的最小堆,存放森林 if (n > DefaultSize) {cerr <<"n out of range" <<endl; return;} for (int i = 0; i < n; i + +) {Node[i].root -> data.key = fr[i]; Node[i].root -> leftchild = Node[i].root -> rightchild = NULL;} hp.MinHeap (Node, n); //构造最小堆 for (int i = 0; i < n – 1 ; i + +) { hp.RemoveMin (first); //选权值最小的树 hp.RemoveMin (second); //选权值次小的树 newtree = new ExtBinTree <Type> (first.second); //构造新的二叉树 hp.Insert (newtree); }} //插入到最小堆中

  17. 三、霍夫曼编码——霍夫曼树应用事例 1、最小冗余编码问题 ☆设用0,1码来对一串字符信息进行等长编码: T —— 00,A —— 01,D —— 10,S —— 11 ☆对于信息串“ ATTSTATADT ”所得到的编码为 01,00,00,11,00,01,00,01,10,00 共20位编码 ☆字母集合{T,A,D,S}出现的频度 W = {5,3,1,1}, 若采用不等长编码表示 T —— 0,A —— 10,D —— 110,S —— 111 所得到的 编码是 10,0,0,111,0,10,0,10,110,0 共17位,这是最小冗 余编码。

  18. 10 0 1 5 T 5 0 1 2 A 3 0 1 D S 1 1 三、霍夫曼编码——霍夫曼树应用事例 2、霍夫曼树编码 ☆以字符的频度为权构造霍夫曼树 ☆左分支表示0,右分支表示1 ☆从根到各外结点路径上经由的数字序列构成各字符的编码 3、霍夫曼树编码的优越性 ☆是最小冗余码 ☆非前缀码——码 Ci 不是码 Cj 的前缀 ☆译码简单唯一——不断从根开始沿霍夫曼编码树查找。 10001110100101100 译码得到的只能是报文串: ATTSTATADT

More Related