算法与数据结构》课程实验报告一、实验目的1、实现二叉树的存储结构2、熟悉二叉树基本术语的含义3、掌握二叉树相关操作的具体实现方法二、实验内容及要求1. 建立二叉树2. 计算结点所在的层次3. 统计结点数量和叶结点数量4. 计算二叉树的高度5. 计算结点的度6. 找结点的双亲和子女7. 二叉树前序、中序、后序遍历的递归实现和非递归实现及层次遍历8. 二叉树的复制9. 二叉树的输出等三、系统分析(1)数据方面:该二叉树数据元素采用字符char 型,并且约定“ #”作为二叉树输入结束标识符。
并在此基础上进行二叉树相关操作。
(2)功能方面:能够实现二叉树的一些基本操作,主要包括:1. 采用广义表建立二叉树。
2. 计算二叉树高度、统计结点数量、叶节点数量、计算每个结点的度、结点所在层次。
3. 判断结点是否存在二叉树中。
4. 寻找结点父结点、子女结点。
5. 递归、非递归两种方式输出二叉树前序、中序、后序遍历。
6. 进行二叉树的复制。
四、系统设计(1)设计的主要思路二叉树是的结点是一个有限集合,该集合或者为空,或者是由一个根节点加上两棵分别称为左子树和右子树、互不相交的二叉树组成。
根据实验要求,以及课上老师对于二叉树存储结构、基本应用的讲解,同时课后研究书中涉及二叉树代码完成二叉树模板类,并将所需实现各个功能代码编写完成,在建立菜单对功能进行调试。
(2)数据结构的设计二叉树的存储结构有数组方式和链表方式。
但用数组来存储二叉树有可能会消耗大量的存储空间,故在此选用链表存储,提高存储空间的利用率。
根据二叉树的定义,二叉树的每一个结点可以有两个分支,分别指向结点的左、右子树。
因此,二叉树的结点至少应包括三个域,分别存放结点的数据,左子女结点指针,右子女结点指针。
这将有利于查找到某个结点的左子女与右子女,但要找到它的父结点较为困难。
该实验采取二叉链表存储二叉树中元素,具体二叉树链表表示如下图所示。
图1 二叉树的链表表示(3)基本操作的设计二叉树关键主要算法:利用广义表进行二叉树的建立。
该算法首先通过重载输入符号,在重载函数中调用CreatBinTree 函数,该函数有两个参数,第一个参数为输入流,用于传递用户输入的二叉树字符串,第二个参数则是二叉树的根结点root。
再通过栈操作是实现二叉树。
递归与非递归两种方式实现前序、中序、后序的遍历。
递归实现三种遍历的函数均只有一个参数即二叉树根节点root,递归结束条件则是结点为空。
当结点不为空时,根据三种遍历的方式不同而代码顺序不同。
其中前序遍历访问结点顺序是:根结点、左子树、右子树;中序遍历访问结点顺序是:左子树、根结点、右子树;后序遍历访问结点顺序是:左子树、右子树、根结点。
具体算法以及流程图见报告实验分析部分。
涉及二叉树性质的一些计算例如树的高度,结点所处层次,结点的度等。
在进行二叉树相关性质计算函数中参数为二叉树根节点root,再通过需要计算不同性质实现不同递归代码。
需要注意的是不同计算的递归结束条件不同对于结点父节点与子女结点的寻找。
对于结点父结点与子女结点的查找函数均有2 个参数,一个是二叉树根结点root 以及需要查找结点的数据域data。
具体实现方式是通过递归遍历每一个二叉树结点,当匹配到需要查找结点数据域时再进行对于该结点父结点或子女结点的输出,若未匹配成功则输出二叉树中不存在该结点。
五、编程环境与实验步骤(1)编程环境操作系统:Windows 操作系统;编程工具软件:Visual Studio 2017(2)实验步骤程序相关文件有:BinTreeNode.h、BinaryTree.h、Queue.h、SeqStack.h四个头文件以及主函数调试文件main.cpp(3)编译参数无编译参数,在Vs2017 或其他版本中新建项目然后将程序相关文件添加到解决方案中对应位置中调试即可。
六、实现代码#include "BinTreeNode.h"#include "SeqStack.h"#include "Queue.h"enum tag { L, R };extern int number;extern bool flag;extern bool flag1;extern bool flag2;template <class T>class BinaryTree {public :BinTreeNode <T> *root; // 二叉树根指针T RefValue; // 数据输入停止标志public :BinaryTree() {root = NULL;}BinaryTree( T value ) {root = NULL;RefValue = value ;BinaryTree( BinaryTree <T> &s) { root = Copy( s.root);} // 复制构造函数BinTreeNode <T> *Copy( BinTreeNode<T> * orignode );~BinaryTree(){ destroy(root); }void destroy( BinTreeNode<T> *& subTree );void Find_Father( BinTreeNode <T> *(& subTree ), T data ); // 找父节点void Find_Children( BinTreeNode <T> *(& subTree ), T data ); // 找子女节点void Find( BinTreeNode <T> *(& subTree ), T data ); // 查找结点int Height( BinTreeNode <T> * subTree ); // 返回树高度int Size( BinTreeNode <T> * subTree ); // 返回结点数void level( BinTreeNode <T> * subTree ); // 返回结点所在层次void Dujisuan( BinTreeNode <T> * subTree ); // 返回结点的度以及叶节点个数BinTreeNode <T> *getRoot() { return root; } // 取根bool Isempty() { return (root == NULL) ? true : false ; } // 判二叉树是否为空voiddgpreOrder( BinTreeNode <T> * subTree ); // 递归实现前序遍历void dginOrder( BinTreeNode <T> * subTree ); // 递归实现中序遍历void dgpostOrder( BinTreeNode <T> * subTree ); // 递归实现后序遍历void PrintBTree( BinTreeNode <T> * BT);void preOrder( BinTreeNode <T> * subTree ); // 非递归实现前序遍历void inOrder( BinTreeNode<T> * subTree ); // 非递归实现中序遍历void postOrder( BinTreeNode <T> * subTree ); // 非递归实现后序遍历void CreateBinTree( istream & in , BinTreeNode <T> *& BT); void Traverse( BinTreeNode <T> * subTree , ostream &out );template <class T>friend istream & operator>>( istream &in , BinaryTree <T> & Tree ); // 重载操作:输入template <class T>friend ostream & operator<<( ostream &out , BinaryTree <T> & Tree ); // 重载操作:输出};template <class T> void BinaryTree <T>::destroy( BinTreeNode <T> *& subTree ) {if ( subTree != NULL) {destroy( subTree ->leftChild); destroy( subTree ->rightChild); delete subTree;} }template <class T> void BinaryTree <T>::CreateBinTree( istream & in , BinTreeNode<T> *& BT) { SeqStack<BinTreeNode <T> *> s;BT = NULL; // 置空二叉树BinTreeNode <T> *p, *t; int k=0; T ch;in >> ch;while (ch != RefValue) {switch (ch) {case '(' :s.Push(p); k = 1; break ;case ')' :s.Pop(t); break ;case ',' :k = 2; break ; default :p = new BinTreeNode <T>(ch);if ( BT == NULL ) BT = p; else if (k == 1) { s.getTop(t); t->leftChild = p;} if (k==2) { s.getTop(t); t->rightChild = p;} } in >> ch;}} template <class T> void BinaryTree <T>::Traverse( BinTreeNode <T> * subTree, ostream &out) { if ( subTree != NULL) {out << subTree->data << " " ; Traverse( subTree ->leftChild, o ut );Traverse( subTree->rightChild, out);}}template <class T>void BinaryTree <T>::dginOrder( BinTreeNode<T> * subTree ) { if ( subTree != NULL){dginOrder( subTree ->leftChild); cout << subTree ->data << " " ; dginOrder( subTree ->rightChild);} } template <class T> void BinaryTree <T>::dgpostOrder( BinTreeNode <T> * subTree ) {if ( subTree != NULL) { dgpostOrder( subTree ->leftChild); dgpostOrder( subTree ->rightChild); cout << subTree ->data << " " ;}template <class T>void BinaryTree <T>::dgpreOrder( BinTreeNode <T> * subTree ) { if ( subTree != NULL) {cout << subTree ->data << " " ; dgpreOrder( subTree ->leftChild); dgpreOrder( subTree ->rightChild);}}template <class T>int BinaryTree <T>::Height( BinTreeNode<T> * subTree ) { if ( subTree == NULL)return 0;else {int i = Height( subTree ->leftChild);int j = Height( subTree ->rightChild); return (i < j) ? j + 1 : i + 1;}}template <class T>int BinaryTree <T>::Size( BinTreeNode<T> * subTree ) { if ( subTree == NULL)return 0;elsereturn 1 + Size( subTree ->leftChild) + Size( subTree ->rightChild);}template <class T>void BinaryTree <T>::PrintBTree( BinTreeNode <T> * BT) { if ( BT != NULL) {cout << BT->data;if ( BT->leftChild != NULL || BT->rightChild != NULL) {cout << "(" ;PrintBTree( BT->leftChild);cout << "," ;if ( BT->rightChild != NULL) PrintBTree( BT->rightChild);cout << " ) ";}}}template <class T>void BinaryTree <T>::preOrder( BinTreeNode <T> * subTree ) { SeqStack<BinTreeNode <T> *> S;BinTreeNode <T> *p = subTree ; BinTreeNode <T> *n = NULL;S.Push(n); while (p != NULL) { cout << p->data << " " ;if (p->rightChild != NULL) S.Push(p->rightChild); if (p->leftChild != NULL) p = p->leftChild; elseS.Pop(p);}} template <class T> void BinaryTree <T>::inOrder( BinTreeNode <T> * subTree ) {SeqStack<BinTreeNode <T> *> S;BinTreeNode <T> *p = root;BinTreeNode <T> *n = NULL; S.Push(n);do { while (p != NULL) {S.Push(p); p = p->leftChild;}if (!S.IsEmpty()) { S.Pop(p); if (p != n) { cout << p->data << " " ; p = p->rightChild;}}} while (p != NULL || !S.IsEmpty());} template <class T> struct stkNode {BinTreeNode <T> *ptr;tag ta;stkNode( BinTreeNode<T> * N = NULL) :ptr( N), ta( L) {} };template <class T>void BinaryTree <T>::postOrder( BinTreeNode<T> * subTree ) { SeqStack<stkNode <T>> S; stkNode <T> w;BinTreeNode <T> *p = root;do {while (p != NULL) {w.ptr = p; w.ta = L; S.Push(w);p = p->leftChild;} int continuel = 1; while (continuel && !S.IsEmpty()) { S.Pop(w); p = w.ptr; switch (w.ta) { case L:w.ta= R; S.Push(w);continuel = 0; p = p->rightChild; break ;case R:cout << p->data << " " ; break ;} }} while (!S.IsEmpty());cout << endl;} template <class T> istream &operator>> ( istream &in, BinaryTree <T>& Tree) {Tree .CreateBinTree( in , Tree .root); return in ;}template <class T> ostream &operator<< ( ostream & out, BinaryTree <T>& Tree) { out << " 二叉树的前序遍历" << endl;Tree .Traverse( Tree.root, out);out << endl; returnout;} template <class T>BinTreeNode<T> * BinaryTree <T>::Copy( BinTreeNode <T> * orignode ) { if ( orignode == NULL) return NULL;BinTreeNode <T> *temp = new BinTreeNode<T>; temp->data = orignode ->data;temp->leftChild = Copy( orignode ->leftChild); temp->rightChild = Copy( orignode ->rightChild); return temp;} template <class T> void BinaryTree <T>::level( BinTreeNode<T> * subTree ) {if ( subTree == NULL) return ;else {Queue<BinTreeNode <T> *> Q; BinTreeNode<T> *n; n = NULL;Q.EnQueue(subTree );Q.EnQueue(n);int level = 1;while (!Q.IsEmpty()) { BinTreeNode <T> *node; Q.DeQueue(node); if ( NULL == node) { if(Q.IsEmpty()) break ;level++; Q.EnQueue(n); continue ;}cout << "第" << level << "层结点:" << node->data << endl; if ( NULL != node->leftChild) Q.EnQueue(node->leftChild);if ( NULL != node->rightChild) Q.EnQueue(node->rightChild);}}}template <class T>void BinaryTree <T>::Dujisuan( BinTreeNode <T> * subTree ) {if ( subTree == NULL) return ;else {Queue<BinTreeNode <T> *> Q; int count = -1;Q.EnQueue(subTree );while (!Q.IsEmpty()) { BinTreeNode <T> *node; Q.DeQueue(node); if (node->leftChild != NULL && node->rightChild != NULL)count = 2;else if (node->leftChild == NULL && node->rightChild == NULL){count = 0; number++;}elsecount = 1;cout << node->data<< " 的度为:" <<count<< endl; if ( NULL != node->leftChild)Dujisuan(node->leftChild);if ( NULL != node->rightChild) Dujisuan(node->rightChild);}}}template <class T>void BinaryTree <T>::Find_Father( BinTreeNode<T> *(& subTree ), T data ) // 找父节点利用了递归的思想,基本结构还是前序遍历{if ( subTree == NULL)return ;if ( subTree->leftChild != NULL) // 当左孩子存在的时候才进行判断,否则程序出错{if ( subTree ->leftChild->data == data){cout << " 该节点的父结点是:" << subTree ->data<<endl;flag = true ;// 全局变量设置了一个标志flag=false ,如果找到父结点,则flag 赋值为true}}if ( subTree ->rightChild != NULL) // 如左子树所示{if ( subTree ->rightChild->data == data){cout << " 该节点的父结点是:" << subTree ->data<<endl; flag = true ;}}Find_Father( subTree ->leftChild, data );Find_Father( subTree ->rightChild, data );}template <class T>void BinaryTree <T>::Find_Children( BinTreeNode <T> *(& subTree ), T data )// 找子女节点利用了递归的思想,基本结构还是前序遍历{ if ( subTree == NULL)return ;else {if ( subTree ->data == data){flag2 = true ; // 全局变量设置了一个标志flag2=false ,如果找到父结点,则flag2赋值为 true}template <class T> void BinaryTree <T>::Find( BinTreeNode <T> *(&subTree ), T data) { if ( subTree == NULL)return ; else {if ( subTree ->data == data) flag1 = true ; else {Find( subTree ->leftChild, data ); Find( subTree ->rightChild,data );}}七、测试结果与说明菜单界面:if ( subTree ->leftChild != NULL) {cout << " 该节点的左子女结点是 :}if ( subTree ->rightChild != NULL) {cout << " 该节点的右子女结点是 :}if ( subTree ->leftChild == NULL) {cout << " 该节点的左子女结点为空}if ( subTree ->rightChild == NULL) {cout << " 该节点的右子女结点为空}}else {Find_Children( subTree ->leftChild, Find_Children( subTree ->rightChild,<< subTree ->leftChild->data << endl;<< subTree->rightChild->data << endl;<< endl;<< endl;data ); data );二叉树建立:二叉树高度计算:统计结点数量:结点度计算以及叶节点数量:结点所在层次计算:查找结点是否在树中:查找结点父结点:查找结点子女结点;二叉树输出结果(前序)三种方式(前序、中序、后序)输出二叉树(递归)三种方式(前序、中序、后序)输出二叉树(非递归)二叉树复制:八、实验分析(1)算法的性能分析二叉树涉及主要算法有利用广义表进行二叉树的建立、递归与非递归两种方式实现前序、中序、后序的遍历、二叉树性质的一些计算例如树的高度,结点所处层次,结点的度等。