当前位置:
文档之家› 北京邮电大学数据结构实验报告与源代码实验三二叉树
北京邮电大学数据结构实验报告与源代码实验三二叉树
2.1 存储结构
采用二叉树的存储结构,其中每个二叉树的结点定义了一个结构体,该结构体包 含三个元素,分别是一个 T 类型的数据域 data,一个指向 T 类型的指针左孩子, 一个指向 T 类型的指针右孩子,示意图如图所示。
第1页
北京邮电大学信息与通信工程学院
第6页
北京邮电大学信息与通信工程学院
}
if (R==NULL) return d; if ((R->lch==NULL) && (R->rch==NULL)) return d+1; else { int m = GetDepth(R->lch,d+1); int n = GetDepth(R->rch,d+1); return n>m? n:m; } 1
2
3
第7页
北京邮电大学信息与通信工程学院
八:求二叉树的叶子结点数: A.自然语言描述: 1:判断根节点是否为空,如果为空,返回 0 2:如果根节点不为空,切根节点的左右孩子同时为空,返回 1 3:递归调用求二叉树的叶子节点数函数,参数改为根节点的左孩子 4:递归调用求二叉树的叶子结点数函数,参数改为根节点的右孩子 5:返回根节点的左右子树的叶子结点数之和 B.代码详细分析: template <class T> int BiTree<T>::LeafNodeCount(Node<T> *R) { if (R==NULL) return 0; if ((R->lch==NULL) && (R->rch==NULL)) return 1; else { int n=LeafNodeCount(R->lch); int m=LeafNodeCount(R->rch); return m+n; } 1 }
2
3
六:求二叉树的深度: A.自然语言描述: 1:判断根节点是否为空,如果根节点为空,返回 0 2:如果根节点不为空但是根节点的左右孩子同时为空,返回 1 3:如果以上两个条件都不成立 4:递归调用求二叉树的深度,函数的参数改为根节点的左孩子,并且深度初始化 为1 5:递归调用求二叉树的深度,函数的参数改为跟结点的右孩子,并且深度初始化 为0 6:返回 4 与 5 步中得出深度较大的那个数作为二叉树的深度数 B.代码详细分析: template <class T> int BiTree<T>::GetDepth(Node<T> *R,int d) {
第3页
北京邮电大学信息与通信工程学院
}
三:中序遍历二叉树: A.自然语言描述: 1:建立栈 2:判断该栈是否为空并且根节点是否为空指针 3:如果根节点不是空指针,将它入栈 4:入栈后将根节点指针指向它的左孩子 5:如果根节点是空指针 6:则根节点出栈,输出该节点的 data 域,并且指向根节点的指针指向它的右孩子 B. 代码详细分析: template <class T> void BiTree<T>::Inorder(Node<T> *R) { Stack<Node<T>*> S; while(!S.IsEmpty() || (R!=NULL)) { if (R!=NULL) { S.Push(R); R=R->lch; } else { R=S.Pop(); Print(R->data); R=R->rch; } }
第4页
北京邮电大学信息与通信工程学院
}
四:后序遍历二叉树: A.自然语言描述: 1:判断根节点是否为空 2:如果根节点不为空 3:递归调用后续遍历函数,函数的参数改为根节点的左孩子 4:递归调用后续遍历函数,函数的参数改为根节点的右孩子 5:输出根节点的 data 域 B.代码详细分析: template <class T> void BiTree<T>::Postorder(Node<T> *R) { if (R!=NULL) { Postorder(R->lch); Postorder(R->rch); Print(R->data); } 1 }
第8页
北京邮电大学信息与通信工程学院
int n=NodeCount(R->rch); return m+n+1; } } 1
2
3
2.3 其他
对二叉树的操作上,前序遍历与中序遍历采用了非递归算法,后续遍历,层序遍历,求 二叉树深度,求二叉树叶子结点数,求二叉树结点数等函数采用了递归算法。为了提高运算 性能,可以将它们改为非递归算法来实现,例如,后续遍历的非递归算法如下: template <class T> void BiTreee<T>::Postorder (Node<T> *R) { Stack<SNode<T>*> S; SNode<T> *p; do { while (R!=NULL) { p->ptr=R; p->tag=1;S.Push(p); R=R->lch; } while(!S.IsEmpty() && S.GetTop()->tag==2) { p=S.Pop(); cout<<p->ptr->data; } if(!S.IsEmpty()) { S.GetTop()->tag=2; R=S.GetTop()->ptr->rch; } } while(!S.IsEmpty())
2
3
九:求二叉树的结点数: A.自然语言描述: 1:判断根节点是否为空,如果为空,返回 0 2:如果根节点不为空 3:递归调用求二叉树的结点数的函数,参数改为根节点的左孩子 4:递归调用求二叉树的结点数的函数,参数改为根节点的右孩子 5:返回根节点的左右字数的结点数之和 B.代码详细分析: template <class T> int BiTree<T>::NodeCount(Node<T> *R) { if (R==NULL) return 0; else { int m=NodeCount(R->lch);
3. 程序运行结果
主函数流程图如下:
第9页
北京邮电大学信息与通信工程学院
开始
初始化一个对象
初始化字符型数组,作为赋值准备
利用 creat 函数初始化一个二叉树,参数为初始化的字符型数组
执行前序,后序,中序,层序遍历,输出遍历结果
执行求结点数,叶子节点数,二叉树深度,路径函数
执行查找数中结点元素函数
结束
第 10 页
北京邮电大学信息与通信工程学院
程序运行截图如下:
4. 总结
对二叉树的操作上,前序遍历与中序遍历采用了非递归算法,后续遍历,层序遍历,求 二叉树深度,求二叉树叶子结点数,求二叉树结点数等函数采用了递归算法。为了提高运算 性能,可以将它们改为非递归算法来实现,对于比较复杂的算法,递归和非递归的运算时间 复杂度差别较大,从性能考虑,应当优先采用非递归算法
第2页
北京邮电大学信息与通信工程学院
Create(R->lch, buf, 2*i); Create(R->rch, buf, 2*i+1); } }
A[i-1]
lch
A[2*i]
data
rch
A[2*i+1]
lch
data
rch
lch
data
rch
重复上述赋值过程,实 现递归调用 二:前序遍历二叉树: A. 自然语言描述: 1:建立栈 2:判断该栈是否为空并且根节点是否为空指针 3:如果根节点不是空指针,则输出它的 data 域,并且是它入栈 4:入栈后将根节点指针指向它的左孩子 5:如果根节点是空指针 6:则根节点出栈,并且指向根节点的指针指向它的右孩子 B.代码详细分析: template <class T> void BiTree<T>::Preorder(Node<T> *R) { Stack<Node<T>*> S; while(!S.IsEmpty() || (R!=NULL)) { if (R!=NULL) { Print(R->data); S.Push(R); R=R->lch; } else { R=S.Pop(); R=R->rch; } }
第 11 页
北京邮电大学信息与通信工程学院
源代码
使用说明:新建头文件“Function.h”和代码文件“main.cpp”, 将以下两部分代码复制到相应的头文件和代码文件后 ctrl+F5 运行即 可
Function.h:
#include<iostream> using namespace std; template <class T> class Node { public: T data; Node<T>* lch; Node<T>* rch; int ltag; int rtag; Node():lch(NULL),rch(NULL),ltag(0),rtag(0){} }; template <class T> class stacknode { public: Node<T> * treenode; int tag; }; template <class T> class BiTree {
2.2 关键算法分析
一:二叉树的建立: A. 自然语言描述: 1 首先判断调用的数组是否为空,如果为空,直接将一个已经初始化好的根节点置 为空。 2 如果该数组不为空,则把调用的数组的第一个元素的赋给根节点的 data 域。 3 采用递归的思想,分别将根节点的左右孩子作为根节点,递归调用该函数。完成 对左右子树的赋值。 B. 代码详细分析: template <class T> void BiTree<T>::Create(Node<T> *&R,T* buf,int i) { if (buf[i-1]==0) R = NULL; else { R=new Node<T>; R->data = buf[i-1];