当前位置:文档之家› 南邮数据结构上机实验二二叉树的基本操作及哈夫曼编码译码系统的实现

南邮数据结构上机实验二二叉树的基本操作及哈夫曼编码译码系统的实现

实验报告(2015 / 2016学年第二学期)课程名称数据结构A实验名称二叉树的基本操作及哈夫曼编码译码系统的实现实验时间2016 年 4 月14 日指导单位计算机科学与技术系指导教师骆健学生姓名班级学号学院(系) 管理学院专业信息管理与信息系统实习题名:二叉树的基本操作班级姓名学号日期2016.04.14一、问题描述设计递归算法,实现下列二叉树运算:删除一棵二叉树、求一棵二叉树的高度、求一棵二叉树中叶子结点数、复制一棵二叉树、交换一棵二叉树的左右子树。

设计算法,按自上到下,从左到右的顺序,按层次遍历一棵二叉树。

设计main函数,测试上述每个运算。

二、概要设计文件tree.cpp中在该文件中定义二叉树的链式存储结构,用队列实现二叉树的层次遍历,并且编写实现二叉树的各种基本操作函数。

其中包括结点类BTNode,循环队列类SeqQueue,二叉树类BinaryTree。

主函数main的代码如图所示。

三、详细设计1.类和类的层次设计程序定义了循环队列SeqQueue类和二叉树BinaryTree类。

SeqQueue类主要是用队列实现,层次遍历。

运用后序遍历思想,把树分解为左右子树和跟结点再进行左右交换并计算树的高度,最后删除二叉树。

(b)二叉树类2.核心算法程序利用循环队列SeqQueue类通过不断出队并输出节点的值,将左右孩子入队直到队列为空实现二叉树的层次遍历。

并运用后序遍历思想,将二叉树树分解为左右子树和根结点,利用(p -> lChild)和(p -> rChild)计算结点数目,并通过交换结点的左右子树实现左右交换,计算树的高度,最后删除二叉树。

核心算法主要是二叉树BinaryTree类中的High,Node_num,Exchange,Level_traversal四个函数,其设计流程图如下:High()Node_num()Exchange()Level_traversal()四、程序代码template<class T>int BinaryTree<T>::Node_num(BTNode<T>*p) //叶子结点{if(p){if(p -> lChild == NULL && p -> rChild == NULL)return 1;elsereturn Node_num(p -> lChild) + Node_num(p -> rChild);}elsereturn 0;}template<class T>void BinaryTree<T>::Exchange(BTNode<T>*&t) //左右子树交换{if(t){BTNode<T>*q = t -> lChild;t -> lChild = t->rChild;t -> rChild = q;Exchange(t -> lChild);Exchange(t -> rChild);}}template<class T>void BinaryTree<T>::Level_traversal(void(*Visit)(T&x)) //层次遍历{Level_traversal(Visit, root);cout << endl;}template<class T>void BinaryTree<T>::Level_traversal(void(*Visit)(T&x),BTNode<T>*t) //层次遍历{BTNode<T> *a;Visit(t -> element);if(t -> lChild)s.EnQueue(t -> lChild);if(t -> rChild)s.EnQueue(t -> rChild);while(s.Front(a) == true){if(a -> lChild)s.EnQueue(a -> lChild);if(a -> rChild)s.EnQueue(a -> rChild);Visit(a -> element);s.DeQueue();}}五、测试和调试1.测试用例和结果测试结果如下图2.结果分析1)程序能够正确的实现二叉树的基本的建立、删除、复制、遍历以及结点计算等基本操作。

2)由测试结果来看,可以在输出数据时以二叉树图形的形式输出,更简单直观,因此程序还有待改进。

实习题名:哈夫曼编码和译码系统班级姓名学号日期2016.04.14一、问题描述所设计的系统重复显示以下菜单项:B―――建树:读入字符集和各字符频度,建立哈夫曼树。

T―――遍历:先序和中序遍历二叉树。

E―――生成编码:根据已建成的哈夫曼树,产生各字符的哈夫曼编码。

C―――编码:输入由字符集中字符组成的任意字符串,利用已生成的哈夫曼编码进行编码,显示编码结果,并将输入的字符串及其编码结果分别保存在磁盘文件textfile.txt和codefile.txt中。

D―――译码:读入codefile.txt,利用已建成的哈夫曼树进行译码,并将译码结果存入磁盘文件result.txt中。

P―――打印:屏幕显示文件textfile.txt、codefile.txt和result.txt。

X―――退出。

二、概要设计文件Huffman.cpp中定义了四个类,分别是优先权队列类PrioQueue和结点类BTNode、二叉树类BinaryTree以及哈夫曼树类HfmTree,其中哈夫曼树类HfmTree 继承了二叉树类BinaryTree。

主函数mian的代码如图所示:三、详细设计1.类和类的层次结构程序定义了优先权队列类PrioQueue存储元素,为便于实哈夫曼树的建树运算,定义了哈夫曼树类HfmTree是二叉树类BinaryTree的派生类,新增私有的数据成员weight保存二叉树根的权值。

成员函数getW和putW用于存取该值。

2.核心算法定义了类之后,通过函数Make_Ht建树,将相应的字符和权值录入。

通过遍历哈夫曼树,产生每个叶子节点的哈夫曼编码,当遍历访问某个叶节点是,从该结点到根的路径可以确定该叶结点所代表的字符的编码。

实现译码时,首先将字符读入一维数组,根据0或1向左走向右走直到叶子结点,并将结果写入文件中。

其中关键函数编码code和译码Compile以及打印Print的流程图如下。

code()下接下一页CompilePrint()四、程序代码HfmTree<int> Ht;int num;void Make_Ht(){char str[100];int weight[100];cout << "请输入字符个数:";cin >> num; //建树cout << "请输入权值:";for(int i = 0; i < num; i++)cin >> weight[i];cout << "请输入相应字符集:";cin >> str;Ht = CreateHfmTree(weight, str, num);}void Traversal_Ht(){Ht.PreOrder(Visit);Ht.InOrder(Visit);}template<class T>void BinaryTree<T>::Create_code(){Create_code(root);}template<class T>void BinaryTree<T>::Create_code(BTNode<T>*t){if(t){if(t -> parent){for(int j = 0; j <= i; j++)t -> z[j] = t -> parent -> z[j]; //复制双亲的编码域i++;t -> z[i] = t-> val; //在编码域中加入自己的编码}Create_code(t -> lChild); //递归,先左孩子,再右孩子Create_code(t -> rChild);i--;}}template<class T>void BinaryTree<T>::Create_code_out() //生成编码并输出{Create_code_out(root);}template<class T>void BinaryTree<T>::Create_code_out(BTNode<T>*t){if(t){if(t -> lChild == t -> rChild) //叶子结点{cout << t -> ch << ":"; //输出叶子结点中的字符int i = 0;while(t -> z[i] != -1){cout << t -> z[i]; //输出编码域i++;}cout << endl;}Create_code_out(t->lChild);Create_code_out(t->rChild);}}template<class T>void BinaryTree<T>::Code(){Code(root);}template<class T>void BinaryTree<T>::Code(BTNode<T>*t) //编码{ofstream outf("textfile.txt");if(!outf){cout << "Cannot open the file\n";return;}ofstream outs("codefile.txt",ios::trunc);if(!outs){cout << "Cannot open the file\n";return;}outs.close();char str2[100];cout << "请输入由字符集中字符组成的任意字符串: "; cin >> str2;outf << str2;outf.close();int l = strlen(str2);cout << "编码为:" << endl;for(int i = 0; i < l; i++)Make(root, str2[i]);cout << endl;}template<class T>void BinaryTree<T>::Make(BTNode<T> *t,char a){int i = 0;if(t){if(t -> ch == a) //找到相应字符{ofstream outs("codefile.txt",ios::app);while(t -> z[i] != -1){cout << t -> z[i]; //输出编码域outs << t -> z[i]; //将编码写入文件i++;}outs.close();return;}Make(t -> lChild, a);Make(t -> rChild, a);}}template<class T>void BinaryTree<T>::Compile() //译码{Compile(root);}template<class T>void BinaryTree<T>::Compile(BTNode<T> *t){ifstream inf("codefile.txt");if(!inf){cout << "Cannot open the file\n";return;}ofstream outs("result.txt",ios::trunc);if(!outs){cout << "Cannot open the file\n";return;}outs.close();char *re;char tmp;int n = 0;while(inf.get(tmp) != '\0'){n++; //确定字符数量}inf.close();re = new char[n+1];int n2 = 0;ifstream in("codefile.txt");if(!in){cout<<"Cannot open the file\n";return;}while(in.get(tmp) != '\0'){re[n2] = tmp; //将字符读入一位数组n2++;}BTNode<T> *c;cout << "译码为:";int n3 = 0;while(n3 < n){while(t){c = t;if(re[n3] == '0') //左0右1根据0或1向左走向右走直到叶子结点t = t -> lChild;elset = t -> rChild;n3++;}ofstream outs("result.txt",ios::app);if(!outs){cout << "Cannot open the file\n";return;}cout << c -> ch; //输出字符outs << c -> ch; //将结果写进文件outs.close();t = root;n3--;}cout << endl;}void Print(){char str;ifstream a("textfile.txt");ifstream b("codefile.txt");ifstream c("result.txt");if(!a){cout << "Cannot open the file\n";return;}if(!b){cout << "Cannot open the file\n";return;}if(!c){cout << "Cannot open the file\n";return;}cout << "textfile.txt内的内容为:";while(a.get(str) != '\0')cout << str;cout << endl;cout << "codefile.txt内的内容为:";while(b.get(str) != '\0')cout << str;cout << endl;cout << "result.txt内的内容为:";while(c.get(str) != '\0')cout << str;cout << endl;a.close();b.close();c.close();}五、测试和调试1.测试用例和结果1)输入B选择建树操作2)分别输入a,b,c,d以及权值2,4,1,1,建树3)输入T得到该树的遍历4)输入E生成编码5)输入C编码,输入字符串aabdcbdacbdadcdb6)输入D选择译码7)输入P选择打印文件内容8)最后输入X退出2.结果分析1)程序能够完全实现题目的要求,建树,遍历生成编码,编码以及译码打印都能成功完成2)不足之处在于译码方面,不能够实现自己输入一串编码来实现译码,下一步的目标是解决这个问题实习小结通过这次课程设计,使我对二叉树的相关知识有了更深的理解,我们要根据不同的需求,采用不同的数据存储方式,不一定要用栈,二叉树等高级类型,有时用基本的一维数组,只要运用得当,也能达到相同的效果,甚至更好。

相关主题