树和森林的概念 二叉树 (Binary Tree) 二叉树的表示 二叉树遍历 (Binary Tree...

46
树树树树树树树 树树树 ( Binary Tree) 树树树树树树 树树树树树 ( Binary Tree Traversal) ( Heap ) 树树树树 ( Tree & Forest) 树树树树树树 树树树树 ( Huffman Tree)

description

第六章 树与森林. 树和森林的概念 二叉树 (Binary Tree) 二叉树的表示 二叉树遍历 (Binary Tree Traversal) 堆 ( Heap ) 树与森林 (Tree & Forest) 二叉树的计数 霍夫曼树 (Huffman Tree). 6.3.4 、二叉树的计数. 由二叉树的前序序列和中序序列可唯一地确定一棵二叉树。 例 , 前序序列 { ABHFDECKG } 和 中序序列 { HBDFAEKCG }, 构造二叉树过程如下:. 如果前序序列固定不变,给出不同的中序序列,可得到不同的二叉树。. - PowerPoint PPT Presentation

Transcript of 树和森林的概念 二叉树 (Binary Tree) 二叉树的表示 二叉树遍历 (Binary Tree...

Page 1: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

树和森林的概念二叉树 (Binary Tree)二叉树的表示二叉树遍历 (Binary Tree Traversal)堆 ( Heap )树与森林 (Tree & Forest)二叉树的计数霍夫曼树 (Huffman Tree)

Page 2: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

6.3.46.3.4 、二叉树的计数、二叉树的计数由二叉树的前序序列和中序序列可唯一地确定一由二叉树的前序序列和中序序列可唯一地确定一棵二叉树。棵二叉树。例例 , , 前序序列 前序序列 { ABHFDECKG } { ABHFDECKG } 和和中序序列 中序序列 { HBDFAEKCG }, { HBDFAEKCG }, 构造二叉树过程如构造二叉树过程如下:下:

Page 3: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

如果前序序列固定不变,给出不同的中序序列,如果前序序列固定不变,给出不同的中序序列,可得到不同的二叉树。可得到不同的二叉树。

问题是有 问题是有 nn 个数据值,可能构造多少种不个数据值,可能构造多少种不同的二叉树?我们可以固定前序排列,选择所有同的二叉树?我们可以固定前序排列,选择所有可能的中序排列。可能的中序排列。

Page 4: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

例如,有 例如,有 3 3 个数据 个数据 { 1, 2, 3 }{ 1, 2, 3 } ,可得,可得 55种不同的二叉树。它们的前序排列均为种不同的二叉树。它们的前序排列均为 123 ,中序序列可能是中序序列可能是 123123 ,, 132132 ,, 213213 ,, 231231 ,,321321 。。

有有 00 个个 , 1, 1 个个 , 2, 2 个个 , 3, 3 个结点的不同二个结点的不同二叉树如下叉树如下

Page 5: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

例如,具有例如,具有 44 个结点的不同二叉树个结点的不同二叉树b

n nn

n nn nnC

11

112

2

( )!! !

计算具有计算具有 nn 个结点的不同二叉树的棵数个结点的不同二叉树的棵数CatalanCatalan 函数函数

Page 6: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

6.4 线索化二叉树6.4.1 线索 用于指示前驱与后继的指针,加了线索的二叉树叫线索化二叉树

6.4 线索化二叉树

Page 7: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

6.5 6.5 堆 堆 ( Hea( Heap )p )

最小堆 : 任一节点的关键码均小于或等于它的左、右子女的关键码,位于堆顶(即完全二叉树根结点位置)的结点的关键码是整个集合中最小的。最大堆 : 任一节点的关键码均大于或等于它的左、右子女的关键码,位于堆顶(即完全二叉树根结点位置)的结点的关键码是整个集合中最大的。

6.5.1 堆的定义定义

Page 8: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

图例

Page 9: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

最小堆的类定义最小堆的类定义template <class Type> class MinHeap : public MinPQ <Type> {public: MinHeap ( int maxSize ) const; MinHeap ( Type arr[ ], int n ); ~MinHeap ( ) { delete [ ] heap; } const MinHeap<Type> & operator = ( const MinHeap &R ); int Insert ( const Type &x ); int RemoveMin ( Type &x ); int IsEmpty ( ) const { return CurrentSize == 0; }

Page 10: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

int IsFull ( ) const { return CurrentSize == MaxHeapSize; } void MakeEmpty ( ) { CurrentSize = 0; }private: enum { DefaultSize = 10 }; Type *heap; int CurrentSize; int MaxHeapSize; void FilterDown ( int i, int m ); void FilterUp ( int i );}

Page 11: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

6.5.2 6.5.2 堆的建立堆的建立方法一:通过构造函数方法一:通过构造函数 MinHeap 建空堆template <class Type> MinHeap <Type>::MinHeap ( int maxSize ) {// 根据给定大小 maxSize, 建立堆对象 MaxHeapSize = DefaultSize < maxSize ? maxSize : DefaultSize; // 确定堆大小 heap = new Type [MaxHeapSize]; // 创建堆空间 CurrentSize = 0; // 初始化}template <class Type> MinHeap <Type>:: MinHeap ( Type arr[ ], int n ) {// 根据给定数组中的数据和大小 ,建立堆对象

Page 12: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

方法二:复制一个记录数组并对其加以调方法二:复制一个记录数组并对其加以调整形成一个堆整形成一个堆算法:template <class Type> MinHeap <Type>:: MinHeap ( Type arr[ ], int n ) {// 根据给定数组中的数据和大小 ,建立堆对象

Page 13: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

MaxHeapSize = DefaultSize < n ? n : DefaultSize; heap = new Type [MaxHeapSize]; heap = arr; // 数组传送 CurrentSize = n; // 当前堆大小 int currentPos = (CurrentSize-2)/2; // 最后非叶 while ( currentPos >= 0 ) { // 从下到上逐步扩大 ,形成堆 FilterDown ( currentPos, CurrentSize-1 ); // 从 currentPos 开始 , 到 CurrentSize 为止 , 调整 currentPos--; }}

Page 14: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

template <class Type> void MinHeap<Type>:: FilterDown ( const int start, const int EndOfHeap ) { int i = start, j = 2*i+1; // j 是 i 的左子女 Type temp = heap[i]; while ( j <= EndOfHeap ) { if ( j < EndOfHeap && heap[j].key > heap[j+1].key ) j++; // 两子女中选小者 if ( temp.key <= heap[j].key ) break; else { heap[i] = heap[j]; i = j; j = 2*j+1; } } heap[i] = temp;}

Page 15: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

自下向上逐步调整为最小堆

图例图例

Page 16: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

6.5.3 6.5.3 堆的插入与删除堆的插入与删除插入插入算法:template <class Type> int MinHeap<Type>::Insert ( const Type &x ) {// 在堆中插入新元素 x if ( CurrentSize == MaxHeapSize ) // 堆满 { cout << " 堆已满 " << endl; return 0; } heap[CurrentSize] = x; // 插在表尾 FilterUp (CurrentSize); // 向上调整为堆 CurrentSize++; // 堆元素增一 return 1;}

Page 17: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

template <class Type> void MinHeap<Type>::FilterUp ( int start ) {// 从 start 开始 , 向上直到 0, 调整堆 int j = start, i = (j-1)/2; // i 是 j 的双亲 Type temp = heap[j]; while ( j > 0 ) { if ( heap[i].key <= temp.key ) break; else { heap[j] = heap[i]; j = i; i = (i -1)/2; } } heap[j] = temp;}

Page 18: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

最最小小堆堆的的向向上上调调整整

图例

Page 19: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

删除template <class Type> int MinHeap <Type>::RemoveMin ( Type &x ) { if ( !CurrentSize ) { cout << “ 堆已空 " << endl; return 0; } x = heap[0]; // 最小元素出队列 heap[0] = heap[CurrentSize-1]; CurrentSize--; // 用最小元素填补 FilterDown ( 0, CurrentSize-1 ); // 从 0号位置开始自顶向下调整为堆 return 1;}

Page 20: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

6.6.1 6.6.1 树的存储表示树的存储表示11 、广义表表示、广义表表示

树的广义表表示 ( 结点的 utype 域没有画出 )

6.6 6.6 树与森林树与森林

Page 21: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

22 、双亲表示、双亲表示

Page 22: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

33 、左子女、左子女 -- 右兄弟表示法右兄弟表示法图例图例第一种解决方案第一种解决方案第二种解决方案第二种解决方案

树的左子女树的左子女 -- 右兄弟表示右兄弟表示

data child1

child2 child3 childd

data firstChild nextSibling

Page 23: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

用左子女用左子女 -- 右兄弟表示实现的树的类定义右兄弟表示实现的树的类定义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) { }};

Page 24: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

template <class Type> class Tree { public: Tree ( ) { root = current = NULL; } int Root(); int leftchild(); int RightSibling(); void RemovesubTree(TreeNode<Type> *p); void FindParent(TreeNode<Type> *t,TreeNode <Type> *p); ……private: TreeNode<Type> *root, *current; void PreOrder ( ostream & out, TreeNode<Type> *p ); int Find ( TypeNode<Type> *p, Type target ); void RemovesubTree ( TreeNode<Type> *p ); int FindParent ( TreeNode<Type> *t, *p );}

Page 25: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

6.6.2 6.6.2 森林与二叉树的转换森林与二叉树的转换

森林与二叉树的对应关系森林与二叉树的对应关系

Page 26: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

(1) (1) 森林转化成二叉树的规则森林转化成二叉树的规则 若若 FF 为空为空,即,即 nn = 0 = 0 ,则,则 对应的二叉树对应的二叉树 BB 为空二叉树。为空二叉树。 若若 FF 不空不空,则,则 对应二叉树对应二叉树 BB 的的根根 root root ((BB)) 是是 FF 中中第一棵树第一棵树 TT11 的根的根 root root ((TT11)) ;; 其其左子树为左子树为 BB ( (TT1111, , TT1212, …, , …, TT11mm)) ,其,其中,中, TT1111, , TT1212, …, , …, TT11mm 是是 root root ((TT11)) 的子树;的子树; 其其右子树为右子树为 BB ( (TT22, , TT33, …, , …, TTnn)) ,其中,,其中,TT22, , TT33, …, , …, TTnn 是除是除 TT11 外其它树构成的森林。外其它树构成的森林。

Page 27: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

(2) (2) 二叉树转换为森林的规则二叉树转换为森林的规则 如果如果 BB 为空为空,则,则 对应的森林对应的森林 FF 也为空。也为空。 如果如果 BB 非空非空,则,则 FF 中第一棵树中第一棵树 TT11 的根为的根为 rootroot ;; TT11 的根的子树森林的根的子树森林 { { TT1111, , TT1212, …, , …, TT11mm }} 是是由 由 root root 的左子树 的左子树 LB LB 转换而来,转换而来,FF 中除了 中除了 TT1 1 之外之外其余的树组成的森林其余的树组成的森林 { { TT22, , TT33, …, , …, TTnn } } 是由 是由 roroot ot 的右子树 的右子树 RBRB 转换而成的森林。转换而成的森林。

Page 28: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

6.6.3 6.6.3 树的遍历树的遍历

树的二叉树表示树的二叉树表示

11 、深度优先遍历、深度优先遍历

Page 29: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

(1) (1) 树的先根次序遍历的递归算法树的先根次序遍历的递归算法template <class Type> void Tree<Type>::PreOrder ( ) { if ( !IsEmpty ( ) ) { visit ( ); // 访问根结点 TreeNode<Type> *p = current; // 暂存当前结点 int i = FirstChild ( ); // 当前结点转到长子 while (i) { PreOrder ( ); i = NextSibling ( ); } // 递归先根遍历各棵子树 current = p; // 递归完恢复当前结点 }}

Page 30: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

(2) (2) 树的后根次序遍历的递归算法树的后根次序遍历的递归算法template <class Type> void Tree<Type>::PostOrder ( ) { if ( !IsEmpty ( ) ) { TreeNode<Type> *p = current; // 暂存当前结点 int i = FirstChild ( ); // 当前结点转到长子 while (i) { PostOrder ( ); i = NextSibling ( ); } // 递归后根遍历各棵子树 current = p; // 递归完恢复当前结点 visit ( ); // 访问根结点 }}

Page 31: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

22 、广度优先遍历、广度优先遍历按层次次序遍历树的算法按层次次序遍历树的算法template <class Type> void Tree<Type>::LevelOrder ( ) {

Page 32: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

Queue<TreeNode<Type>*> Qu ( DefaultSize ); if ( ! IsEmpty ( ) ) { TreeNode<Type> *p = current; Qu.EnQueue ( current ); // 根进队列 while ( !Qu.IsEmpty ( ) ) { // 队列不空 current = Qu.DeQueue ( ); visit ( ); // 退出队列 ,访问 FirstChild ( ); // 转向长子 while ( !IsEmpty ( ) ) // 结点指针不空 { Qu.EnQueue ( current ); NextSibling ( ); } } } current = p;}

Page 33: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

6.6.4 6.6.4 森林的遍历森林的遍历

森林的二叉树表示森林的二叉树表示

(1) (1) 先根次序遍历的规则:先根次序遍历的规则:若森林若森林 FF 为空为空 , , 返回;否返回;否则则•访问访问 FF 的第一棵树的根的第一棵树的根结点;结点;• 先根次序遍历第一棵树先根次序遍历第一棵树的子树森林;的子树森林;•先根次序遍历其它树组先根次序遍历其它树组成的森林。成的森林。

Page 34: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

森林的二叉树表示森林的二叉树表示

(2) (2) 后根次序遍历的规则:后根次序遍历的规则: 若森林若森林 FF 为空,返回;否为空,返回;否则则•后根次序遍历第一棵树后根次序遍历第一棵树的子树森林;的子树森林;•后根次序遍历其它树组后根次序遍历其它树组成的森林;成的森林;•访问访问 FF 的第一棵树的根的第一棵树的根结点结点。

Page 35: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

森林的遍历森林的遍历

森林的二叉树表示森林的二叉树表示

(3) (3) 广度优先遍历广度优先遍历 (( 层次层次序遍历序遍历 ) ) :: 若森林若森林 FF 为空,返回;否为空,返回;否则则•依次遍历各棵树的根结依次遍历各棵树的根结点;点;•依次遍历各棵树根结点依次遍历各棵树根结点的所有子女;的所有子女;•依次遍历这些子女结点依次遍历这些子女结点的子女结点的子女结点。

Page 36: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

具有不同路径长度的二叉树具有不同路径长度的二叉树

6.7 6.7 霍夫曼树霍夫曼树 (Huffman Tr(Huffman Tree)ee)6.7.1 6.7.1 路径长度 路径长度 (Path Length)(Path Length) 两个结点之间的路径长度是连接两结点的路两个结点之间的路径长度是连接两结点的路径上的分支数。树的路径长度是各结点到根结点径上的分支数。树的路径长度是各结点到根结点的路径长度之和。的路径长度之和。

Page 37: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

nn 个结点的二叉树的路径长度不小于下述数列前个结点的二叉树的路径长度不小于下述数列前nn 项的和,即项的和,即

其路径长度最小者为其路径长度最小者为(( 完全二叉树满足这个条件)完全二叉树满足这个条件)

1

02 1)(log

n

i

iPL

6.7.2 6.7.2 霍夫曼树霍夫曼树带权路径长度 带权路径长度 ( ( Weighted Path Length, Weighted Path Length, WPL )WPL )树的带权路径长度是树的各叶结点所带的权值与树的带权路径长度是树的各叶结点所带的权值与该结点到根的路径长度的乘积的和。该结点到根的路径长度的乘积的和。

1

0

n

iii lwWPL

1

02 1)(log

n

i

iPL

332222110

Page 38: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

具有不同带权路径长度的扩充二叉树具有不同带权路径长度的扩充二叉树

霍夫曼树霍夫曼树 带权路径长度达到最小的扩充二叉树即为霍带权路径长度达到最小的扩充二叉树即为霍夫曼树。夫曼树。 在霍夫曼树中,权值大的结点离根最近。在霍夫曼树中,权值大的结点离根最近。

Page 39: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

霍夫曼算法霍夫曼算法 (1) (1) 由给定的由给定的 nn 个权值个权值 {{ww00, , ww11, , ww22, …, , …, wwnn-1-1}} ,,构造具有构造具有 nn 棵扩充二叉树的森林棵扩充二叉树的森林 FF = { = {TT00, , TT11, , TT22, , …, …, TTnn-1-1}} ,其中每一棵扩充二叉树,其中每一棵扩充二叉树 TTii 只有一个带只有一个带有权值有权值 wwii 的根结点,其左、右子树均为空。的根结点,其左、右子树均为空。 (2) (2) 重复以下步骤重复以下步骤 , , 直到直到 FF 中仅剩下一棵树为止:中仅剩下一棵树为止: ① ① 在在 FF 中选取两棵根结点的权值最小的扩充中选取两棵根结点的权值最小的扩充二叉树二叉树 , , 做为左、右子树构造一棵新的二叉树。做为左、右子树构造一棵新的二叉树。置新的二叉树的根结点的权值为其左、右子树上置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。根结点的权值之和。 ② ② 在在 FF 中删去这两棵二叉树。中删去这两棵二叉树。 ③ ③ 把新的二叉树加入把新的二叉树加入 FF 。。

Page 40: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

霍夫曼树的构造过程霍夫曼树的构造过程

Page 41: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

扩充二叉树的类定义扩充二叉树的类定义template <class Type> class ExtBinTree;template <class Type> class Element {friend class ExtBinTree;private: Type data; Element<Type> *leftChild, *rightChild;};template <class Type> class ExtBinaryTree {public: ExtBinTree ( ExtBinTree<Type> &bt1, ExtBinTree<Type> &bt2 ) {

Page 42: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

root→leftChild = bt1.root; root→rightChild = bt2.root; root→data.key = bt1.root→data.key + bt2.root→data.key; }protected: const int DefaultSize = 20; Element <Type> *root; // 扩充二叉树的根 MinHeap < ExtBinTree <Type> > hp; // 最小堆}

Page 43: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

建立霍夫曼树的算法建立霍夫曼树的算法template <class Type> void HuffmanTree (Type *fr, int n, ExtBinTree <Type> & newtree ) { ExtBinTree <Type> & first, & second; ExtBinTree <Type> Node[DafualtSize]; if ( n > DefaultSize ) { cout << “ 大小 n ” << n << “超出了数组边界 ” << 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; } // 传送初始权值

Page 44: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

hp.MinHeap ( Node, n ); for ( int i = 0; i < n-1; i++ ) { // 建立霍夫曼树的过程,做 n-1趟 hp.DeleteMin ( first ); // 选根权值最小的树 hp.DeleteMin ( second ); // 选根权值次小的树 newtree = new ExtBinTree <Type> ( first, second ); // 建新的根结点 hp.Insert ( newtree ); // 形成新树插入 } return hp.RemoveMin ( newtree );}

Page 45: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

6 .7.3 6 .7.3 霍夫曼编码霍夫曼编码 主要用途是实现数据压缩。主要用途是实现数据压缩。 设给出一段报文: 设给出一段报文: CAST CAST SAT AT A TASACAST CAST SAT AT A TASA 字符集合是 字符集合是 { C, A, S, T }{ C, A, S, T } ,各个字符出现,各个字符出现的频度的频度 (( 次数次数 )) 是 是 WW== { 2, 7, 4, 5 }{ 2, 7, 4, 5 } 。。 若给每个字符以等长编码若给每个字符以等长编码 AA : 00 T : 10 C : 01 S : 11 : 00 T : 10 C : 01 S : 11则总编码长度为 则总编码长度为 ( 2+7+4+5 ) * 2 = 36.( 2+7+4+5 ) * 2 = 36. 若按各个字符出现的概率不同而给予不等长若按各个字符出现的概率不同而给予不等长编码,可望减少总编码长度。编码,可望减少总编码长度。 因各字符出现的概率为因各字符出现的概率为 { 2/18, 7/18, 4/18, 5{ 2/18, 7/18, 4/18, 5/18 }/18 } 。。

Page 46: 树和森林的概念 二叉树  (Binary Tree) 二叉树的表示 二叉树遍历  (Binary Tree Traversal) 堆 ( Heap ) 树与森林  (Tree & Forest)

化整为 化整为 { 2, 7, 4, 5 }{ 2, 7, 4, 5 } ,以它们为各叶结点上的权,以它们为各叶结点上的权值,建立霍夫曼树。左分支赋 值,建立霍夫曼树。左分支赋 00 ,右分支赋 ,右分支赋 11 ,,得霍夫曼编码得霍夫曼编码 (( 变长编码变长编码 )) 。 。 AA : 0 T : 10 C : 110 S : 111 : 0 T : 10 C : 110 S : 111它的总编码长度:它的总编码长度: 7*1+5*2+( 2+4 )*3 = 357*1+5*2+( 2+4 )*3 = 35 。比。比等长编码的情形要短。等长编码的情形要短。 总编码长度正好等于总编码长度正好等于霍夫曼树的带权路径长霍夫曼树的带权路径长度度 WPLWPL 。。 霍夫曼编码是一种无霍夫曼编码是一种无前缀编码。解码时不会前缀编码。解码时不会混淆。混淆。 霍夫曼编码树霍夫曼编码树