1. 实验名称: 二叉树的基本操作及哈夫曼编码译码系统的实现
2.实验目的:
创建一棵二叉树,实现先序、中序和后序遍历一棵二叉树,计算二叉树结点个数等操作。哈夫曼编码/译码系统。
3. 实验任务:
能成功演示二叉树的有关运算,运算完毕后能成功释放二叉树所有结点占用的系统内存。
4. 实验内容
(1)在二叉链表上实现二叉树运算
a) 设计递归算法,实现二叉树的基本运算:删除一棵二叉树,求一棵二叉树的高度,求一棵二叉树中叶子结点数,复制一棵二叉树,交换一棵二叉树的左右子树。
b) 设计算法,按自上到下,自左到右的次序,即按层次遍历一棵二叉树。
c) 设计main函数,测试上述每个运算。
d) 提示:队列结构可以辅助进行层次遍历,队列的元素类型是指向二叉树结点的指针类型。
(2)哈夫曼编码和译码系统
a) 设计一个菜单可以循环显示
B——建树:读入字符集和各字符频度,建立哈夫曼树。
T——遍历:先序和中序遍历二叉树。
E——生成编码:产生每个字符的哈夫曼编码。
C——编码:输入由字符集中字符组成的任意字符串,利用已经生成的哈夫曼编码进行编码,显示编码结果。
D——译码:利用已建成的哈夫曼树进行译码。
X——退出。
b) 提示:修改二叉树结点类BTNode,增加一个指向双亲的parent域,修改二叉树类
的函数MakeTree设置该域的值;可以通过遍历哈夫曼树生成每个叶子结点的哈夫曼编码。
5. 概要设计
1) 二叉树
首先定义结点类BTNode包括对结点的访问,打印,交换结点左右元素等操作。并将二叉树类BTree声明为友元类。二叉树类中包含了建树,判断二叉树是否为空,求结点数,求高度,删除,交换左右子树,三种次序遍历及按层次遍历,清空二叉树等函数。在主函数中调用实现这些功能。
类和类的层次设计
BTNode |
BTree |
T element; BTNode<T> *lchild, *rchild; |
BTNode<T>* root; |
friend class BTree<T>; friend void Visit(BTNode<T>*p); friend void Print(BTNode<T>*p); friend void ex(BTNode<T>*p); |
bool IsEmpty()const; bool Root(T &x)const; void MakeTree(const T &e ,BTree<T>& left, BTree<T>& right); void BreakTree(T &e ,BTree<T>& left,BTree<T>& right); void PreOrder(void (*Visit)(BTNode<T>* u), BTNode<T>*t); void InOrder(void (*Visit)(BTNode<T>* u), BTNode<T>*t); void PostOrder(void (*Visit)(BTNode<T>* u), BTNode<T>*t); int Size(BTNode<T>* t); int GetHeight(BTNode<T>* t); void BfsOrder(void (*Visit)(BTNode<T>* u), BTNode<T>*t); void Change(BTNode<T> *t); void Clear(BTNode<T> *t); |
主要算法:
PreOrder:输出当前结点元素,左右孩子递归调用函数。
InOrder:左孩子递归调用函数,输出当前结点元素,右孩子递归调用。
PostOrder:左右孩子递归调用函数,输出当前结点元素。
BfsOrder:使用一个队列结构,队列元素是指向结点的指针,将当前结点入队,当队列元素没有全部出队时,队头元素出队,如果有左右孩子,左右孩子进队,循环该操作。
Change:左右孩子递归调用函数,交换当前结点左右孩子。
2) 哈夫曼树
首先定义优先权队列的类PrioQueue,实现Append及Serve,这样就可以实现哈夫曼树的构建。其次修改二叉树结点类BTNode,在增加指向双亲的parent域,修改二叉树类MakeTree函数设置该域的值。在二叉树类中添加编码译码等函数。
类和类的层次设计:
BTree |
PrioQueue |
HfmTree:public BTree |
… |
T *q; int n,maxSize; |
T weight; |
… void CreatCode(BTNode<T>*t);//生成哈夫曼编码 String2Code(BTNode<T>*t,char *s);//翻译成哈夫曼码 Code2String(BTNode<T> *t,char code[],int &i,int l)//从哈夫曼码译出原字符串 |