1.62k likes | 1.79k Views
第六章 树和森林. 树和 二叉树 二叉树遍历 线索二叉树 二叉搜索树 二叉树的计数 堆 树与森林 霍夫曼树及其应用. 一、树和二叉树. 树 tree 的定义 (1) 无结点的树 空树 (2) 非空树 仅有一个 根 结点 其余结点分为若干 互不相交的 子树. A. ········································ 根. 3 度. D. B. C. H. I. J.
E N D
第六章 树和森林 • 树和 二叉树 • 二叉树遍历 • 线索二叉树 • 二叉搜索树 • 二叉树的计数 • 堆 • 树与森林 • 霍夫曼树及其应用
一、树和二叉树 树tree的定义 (1) 无结点的树 空树 (2) 非空树 仅有一个根结点 其余结点分为若干 互不相交的子树
A ········································根 3度 D B C H I J ·············叶 0度 E F G K L M 2个3度点 A,D 2个2度点 B,E 2个1度点 C,H 7个叶 F,G,I,J,K,L,M
A ·············································第一层 ······························第二层 D B C ···············第三层 H I J E F G K L ····································第四层 M 树的深度为4
2.二叉树 每个结点至多有两棵子树,1度或2度 A C B F G D E H I J
设有n2个2度点 则有n2+1个叶片 A C B F G D E H I J 第i层结点至多2i-1个 深度为k,结点至多2k-1个
满二叉树 深度为k,结点数2k-1,每层结点数都最大 A C B F G D E H J K L M N O I
满二叉树 完全二叉树 满二叉树去掉最下层最右边若干结点 A C B F G D E H J K L M N O I 满二叉树也是完全二叉树
n个结点,深度 k=[log2n] +1 完全二叉树 n个结点,深度为k: 2k-1-1<n≤2k-1 2k-1 ≤ n <2k k-1 ≤ log2n <k k-1 = [log2n] k = [log2n] +1 A C B F G D E H I J K L M 1个结点深度为1 2-3个结点深度为2 4-7个结点深度为3 8-15个结点深度为4
完全二叉树 结点i的左子结点是2i 右子结点是2i+1 1 3 2 6 7 4 5 8 9 10 11 12 13 结点i的父结点是[i/2]
二叉树的存储 • 完全二叉树的顺序存储 #define MaxTreeSize 100 typedef TElemTypeSqBiTree[MaxTreeSize]; SqBiTree bt;
结点i的父结点是[(i-1)/2] 完全二叉树 结点i的左子结点是2i+1 右子结点是2i+2 0 2 1 5 6 3 4 7 8 9 10 11 12
二叉树的链式存储 树结点
A C B E F D G H
二叉树结点类的定义 #ifndef TREENODE_CLASS #define TREENODE_CLASS #ifndef NULL const int NULL = 0; #endif // NULL
template <class T>class BinSTree; template <class T> class TreeNode { protected: TreeNode<T> *left, *right; public: Tdata; TreeNode (const T& item, TreeNode<T> *lptr = NULL, TreeNode<T> *rptr = NULL); virtual ~TreeNode(void); TreeNode<T>* Left(void) const; TreeNode<T>* Right(void) const; void GetLeft(TreeNode<T>*lptr); void GetRight(TreeNode<T>*rptr); friend class BinSTree<T>; };
// the pointer NULL assigns an empty tree template <class T> TreeNode<T>::TreeNode (const T& item, TreeNode<T> *lptr, TreeNode<T> *rptr): data(item), left(lptr), right(rptr) {}
// method Left allows the user// to reference the left child template <class T> TreeNode<T>* TreeNode<T>::Left(void) const { // return the private member value left return left; }
// method Left allows the user //to reference the right child template <class T> TreeNode<T>* TreeNode<T>::Right(void) const { // return the private member value right return right; }
// does nothing. //exists so nodes derived from it will be // destroyed properly by delete. //used in Chapter 13 for AVL trees template <class T> TreeNode<T>::~TreeNode(void) {} #endif
二叉树结点的操作函数//treelib.h #ifndef TREE_LIBRARY_FUNCTIONS #define TREE_LIBRARY_FUNCTIONS #include <iostream.h> #include <stdlib.h> #include "treenode.h" #ifndef NULL const int NULL = 0; #endif // NULL
建立一个结点 template <class T> TreeNode<T> *GetTreeNode(T item, TreeNode<T> *lptr= NULL, TreeNode<T> *rptr = NULL) { TreeNode<T> *p; p = new TreeNode<T> (item, lptr, rptr); if (p == NULL) { cerr << "Memory allocation failure!\n"; exit(1); } return p; }
撤销一个结点 template <class T> void FreeTreeNode(TreeNode<T> *p) { delete p; }
创建三棵树 void MakeCharTree(TreeNode<char>* &root, int n) { TreeNode<char> *a, *b, *c, *d, *e, *f, *g, *h, *i; switch(n) { case 0: d = GetTreeNode('D'); e = GetTreeNode('E'); b = GetTreeNode('B',(TreeNode<char> *)NULL, d); c = GetTreeNode('C',e, (TreeNode<char> *)NULL); a = GetTreeNode('A',b, c); root = a; break; A C B D E
case 1: g = GetTreeNode('G'); h = GetTreeNode('H'); i = GetTreeNode('I'); d = GetTreeNode('D'); e = GetTreeNode('E',g, (TreeNode<char> *)NULL); f = GetTreeNode('F',h, i); b = GetTreeNode('B',d, e); c = GetTreeNode('C',(TreeNode<char> *)NULL, f); a = GetTreeNode('A',b, c); root = a; break; A C B F D E G H I
case 2: g = GetTreeNode('G'); h = GetTreeNode('H'); i = GetTreeNode('I'); d = GetTreeNode('D',(TreeNode<char> *)NULL, g); e = GetTreeNode('E',h, i); f = GetTreeNode('F'); • b = GetTreeNode('B',d, (TreeNode<char> *)NULL); c = GetTreeNode('C',e, f); a = GetTreeNode('A',b, c); root = a; break;} } A C B F D E G H I
为代数式 a+b*(c-d)-e/f 建一棵树 使a,b,c,d,e,f为叶,两个数之间的运算符为根. a=GetTreeNode(‘a’,(TreeNode<char>)NULL, (TreeNode<char>)NULL); — p1=GetTreeNode(‘-’,c,d); + / p2=GetTreeNode(‘*’,b,p1); a * e f p3=GetTreeNode(‘+’,a,p2); p4=GetTreeNode(‘/’,e,f); — b p5=GetTreeNode(‘-’,p3,p4); root=p5; c d
二、二叉树的遍历 先序遍历 PreOrderTraverse 先访问根结点 再访问左子树 后访问右子树 中序遍历 InOrderTraverse 先访问左子树 再访问根结点 后访问右子树 后序遍历 PostOrderTraverse 先访问左子树 再访问右子树 后访问根结点 层次遍历(Level Traverse )
先序遍历 template <class T> void Preorder (TreeNode<T> *t, void visit(T& item)) { // the recursive scan terminates on a empty subtree if (t != NULL) { visit(t->data); // visit the node Preorder (t->Left( ), visit); // descend left Preorder (t->Right( ), visit); // descend right } } A C B F D E G H I void print(char& itm){cout<<itm;} Preorder(root,print); ABDEGCFHI
中序遍历 A template <class T> void Inorder (TreeNode<T> *t, void visit(T& item)) { // the recursive scan terminates on a empty subtree if (t != NULL) { Inorder(t->Left( ), visit); // descend left visit(t->data); // visit the node Inorder (t->Right( ), visit); // descend right } } C B F D E G H I DBGEACHFI
后序遍历 A template <class T> void Postorder (TreeNode<T> *t, void visit(T& item)) { // the recursive scan terminates on a empty subtree if (t != NULL) { Postorder (t->Left( ), visit); // descend left Postorder (t->Right( ), visit); // descend right visit(t->data); // visit the node } } C B F D E G H I DGEBHIFCA
二叉树的运算 template <class T> void CountLeaf (TreeNode<T> *t, int& count) { if (t != NULL) {CountLeaf(t->Left( ), count); CountLeaf(t->Right( ), count); if (t->Left( ) == NULL && t->Right( ) == NULL) count++; } }
template <class T> int Depth (TreeNode<T> *t) { int depthLeft, depthRight, depthval; if (t == NULL) depthval = 0; else { depthLeft= Depth(t->Left( )); depthRight= Depth(t->Right( )); depthval = 1 + (depthLeft> depthRight?depthLeft:depthRight); } return depthval; }
template <class T> TreeNode<T> *CopyTree(TreeNode<T> *t) { TreeNode<T> *newlptr, *newrptr, *newnode; if (t == NULL) return NULL; if (t->Left( ) = NULL) newlptr = NULL; else newlptr = CopyTree(t->Left( )); if (t->Right( ) = NULL) newrptr = NULL; else newrptr = CopyTree(t->Right()); newnode = GetTreeNode(t->data, newlptr, newrptr); return newnode; }
template <class T> void DeleteTree(TreeNode<T> *t) { if (t != NULL) { DeleteTree(t->Left()); DeleteTree(t->Right()); FreeTreeNode(t); } }
输入一棵树 A C B 按先序输入一棵树 键盘输入: AB#D##CE### template<class T> void CreateTree(TreeNode<T>*&t ) {TreeNode<T>*l,*r; Tch; cin>>ch; if(ch==‘#’)t=NULL; else{t=GetTreeNode(ch); CreateTree(l); t->GetLeft(l); CreateTree(r);t->GetRight(r);} } D E
template <class T> void ClearTree(TreeNode<T> * &t) { DeleteTree(t); t = NULL; // root now NULL } #endif// TREE_LIBRARY_FUNCTIONS
层次遍历——广度优先法遍历树 A template <class T> void LevelScan(TreeNode<T>*t,void visit(T& item)) {Queue<TreeNode<T>*> Q; TreeNode<T> * p; Q.Qinsert(t); while(!Q.Qempty( )) { p=Q.Qdelete( ); visit(p->data); if(p->Left( )!=NULL)Q.Qinsert(p->Left( )); if(p->Right( )!=NULL)Q.Qinsert(p->Right( )); } } C B ABCDEFGHI F D E G H I
测试 #include <iostream.h> #include "treenode.h" #include "treelib.h" void print(char& item) {cout<<item;} void main(void) { TreeNode<char> *root; MakeCharTree(root, 2); int leafCount = 0; CountLeaf(root, leafCount); cout << "Number of leaf nodes is " << leafCount << endl; cout << "The depth of the tree is " << Depth(root) << endl; CreateTree(root); Postorder(root,print); }
三、线索二叉树 ltag=0 lchild指向左子结点 =1 前驱 rtag=0 rchild指向右子结点 =1 后继 带线索的二叉树,即每个结点都带有指向其前驱和后继的指针的二叉树 优点:遍历查找方便快捷,从任何结点可 以向前向后搜索 用途:需要反复遍历和查找的二叉树
中序线索化树 A C B D E
线索二叉树的结点类#include<iostream.h>#include<stdio.h>typedef enum{ Link, Thread //Link==0; Thread==1;}PointerTag;
template <class T>class ThreadNode{ ThreadNode<T> *left, *right; //pointer PointerTag LTag, RTag; // tags for link or thread public:Tdata;ThreadNode(const T item):data(item),left(NULL),right(NULL),LTag(0),RTag(0) { }}
template <class T>void InOrderThreading(ThreadNode<T>*&thrt, ThreadNode<T>* tree){ ThreadNode<T> *pre;thrt=new ThreadNode<T>; if(!thrt) { cerr<<"Memory overflow!"; exit(1); }thrt->LTag=Link;thrt->RTag=Thread;thrt->right=thrt; //right pointer point to its self
if(tree==NULL) thrt->left=thrt;//if "tree" is empty, //left pointer point to its self either else { thrt->left=tree; pre=thrt; InThreading(tree); pre->RTag=Thread; pre->right=thrt; thrt->right=pre;}}
template <class T>void InThreading(ThreadNode<T> *p){ if(p) { InThreading(p->left); if(p->left==NULL) { p->LTag=Thread;p->left=pre; } if(pre->right==NULL) { pre->RTag=Thread;pre->right=p; }pre=p;InThreading(p->rchild); }}
template <class T>void InOrderTravers(ThreadNode<T>*t , void visit(Titem)){ ThreadNode *p;p = t->left; while(p!=t) { while(p->LTag==Link)p=p->left;visit(p->data); while(p->RTag==Thread&&p->right!=t) { p=p->right;visit(p->data); } p = p->right; }}
四、二叉搜索树 (二叉排序树) 其左非空子树上所有结点的值都小于根结点的值 其右非空子树上所有结点的值都大于根结点的值 左右子树也是二叉搜索树 二叉搜索树的作用:排序,检索 45 57 12 60 50 8 20 3 11 59
二叉搜索树 #ifndef BINARY_SEARCH_TREE_CLASS #define BINARY_SEARCH_TREE_CLASS #include <iostream.h> #include <stdlib.h> #ifndef NULL const int NULL = 0; #endif // NULL #include "treenode.h"
template <class T> class BinSTree { TreeNode<T> *root, *current; int size; TreeNode<T> *GetTreeNode(const T& item, TreeNode<T> *lptr,TreeNode<T> *rptr); void FreeTreeNode(TreeNode<T> *p); TreeNode<T> *CopyTree(TreeNode<T> *t); void DeleteTree(TreeNode<T> *t); TreeNode<T> *FindNode(const T& item, TreeNode<T>* & parent) const;