[BinaryTree] 二叉树类的实现
二叉树结点的抽象数据类型:
template<class T>
class BinaryTreeNode
{
friend class BinaryTree<T>;
private:
T element; //结点的数据域
BinaryTreeNode<T>* LeftChild; //结点的左孩子结点
BinaryTreeNode<T>* RightChild; //结点的右孩子结点
public:
BinaryTreeNode();
BinaryTreeNode(const T& ele);
BinaryTreeNode(const T& ele, BinaryTreeNode<T>* l, BinaryTreeNode<T>* r);
bool isLeaf() const; //判断该结点是否是叶子结点,若是,则返回true
};
二叉树结点函数功能实现:
template<class T>
BinaryTreeNode<T>::BinaryTreeNode()
{
LeftChild = RightChild = NULL;
}
template<class T>
BinaryTreeNode<T>::BinaryTreeNode(const T& ele)
{
element = ele;
LeftChild = RightChild = NULL;
}
template<class T>
BinaryTreeNode<T>::BinaryTreeNode(const T& ele, BinaryTreeNode<T>* l, BinaryTreeNode<T>* r)
{
element = ele;
LeftChild = l;
RightChild = r;
}
template<class T>
bool BinaryTreeNode<T>::isLeaf() const
{
if (LeftChild == NULL && RightChild == NULL)
return true;
else return false;
}
二叉树的抽象数据类型:
template<class T>
class BinaryTree
{
private:
BinaryTreeNode<T>* root;
public:
BinaryTree();
~BinaryTree() {}
bool IsEmpty() const; //判断二叉树是否为空树
BinaryTreeNode<T>* getRoot() const; //返回二叉树的根结点
void breadthFirstOrder(BinaryTreeNode<T>* root);//广度优先遍历以root为根结点的子树
void preOrder(BinaryTreeNode<T>* root); //先序遍历以root为根结点的子树
void inOrder(BinaryTreeNode<T>* root); //中序遍历以root为根结点的子树
void postOrder(BinaryTreeNode<T>* root); //后序遍历以root为根结点的子树
void deleteBinaryTree(BinaryTreeNode<T>* root); //删除以root为根结点的子树
void visit(BinaryTreeNode<T>* pointer); //访问当前结点
BinaryTreeNode<T>* build_from_pre_and_in(char* preorder, char* inorder, int n);
//根据前序和中序遍历表达式构造二叉树
BinaryTreeNode<T>* build_from_post_and_in(char* postorder, char* inorder, int m);
//根据后序和中序遍历表达式构造二叉树
int getRootId1(char *preorder, char *inorder, int n); //返回根结点在中序遍历表达式中序号
int getRootId2(char *postorder, char *inorder, int m); //返回根结点在中序遍历表达式中序号
};
广度优先遍历(队列):
【思路】根结点入队,队列不空循环,访问队头并出队,左子树不空则入队,右子树不空则入队。
template<class T>
void BinaryTree<T>::breadthFirstOrder(BinaryTreeNode<T>* root)
{
queue<BinaryTreeNode<T> *> nodeQueue;
BinaryTreeNode<T> * pointer = root;
if (pointer)
nodeQueue.push(pointer);
while (!nodeQueue.empty())
{
pointer = nodeQueue.front();
visit(pointer);
nodeQueue.pop();
if (pointer->LeftChild)
nodeQueue.push(pointer->LeftChild);
if (pointer->RightChild)
nodeQueue.push(pointer->RightChild);
}
}
先序遍历:
【思路】
1.访问当前结点
2.当前结点的右儿子结点非空,则入栈
3.左儿子结点非空,使之作为当前结点,否则弹出栈顶元素,使之作为当前结点
4.反复执行1、2、3,至栈空为止
template<class T>
void BinaryTree<T>::preOrder(BinaryTreeNode<T>* root)
{
stack<BinaryTreeNode<T> *> nodeStack;
BinaryTreeNode<T> * pointer = root;
while (!nodeStack.empty() || pointer)
{
if (pointer)
{
visit(pointer);
if (pointer->RightChild != NULL)
nodeStack.push(pointer->RightChild);
pointer = pointer->LeftChild;
}
else
{
pointer = nodeStack.top();
nodeStack.pop();
}
}
}
中序遍历:
【思路】
1.每遇到一个结点就把它压栈,然后去遍历其左子树
2.遍历完左子树后,从栈顶弹出这个结点并访问之
3.然后遍历该结点的右子树
template<class T>
void BinaryTree<T>::inOrder(BinaryTreeNode<T>* root)
{
stack<BinaryTreeNode<T> *> nodeStack;
BinaryTreeNode<T> * pointer = root;
while (!nodeStack.empty() || pointer)
{
if (pointer)
{
nodeStack.push(pointer);
pointer = pointer->LeftChild;
}
else
{
pointer = nodeStack.top();
visit(pointer);
pointer = pointer->RightChild;
nodeStack.pop();
}
}
}
后序遍历:
【基本思想】
1.每遇到一个结点,先把它推入栈中,去遍历它的左子树
2.遍历完它的左子树后,应继续遍历该结点的右子树
3.遍历完右子树之后,才从栈顶弹出该结点并访问它
【解决方案】
0.将根结点作为当前结点
1.进栈过程:
a.如果当前结点不空且具有左子树,将当前结点压入栈中,否则进入2
b.将当前结点的左子树的根结点设置为当前结点
c.重复 a
2.出栈过程:
a.如果当前结点不空且没有右子树,或者其右子树的根结点已经访问,访问之,否则进入3
b.若栈空,结束,否则取出当前栈顶结点作为当前结点
c.重复 a
3.将当前结点压入栈中
4.将当前结点的右子树的根结点设为当前结点,重复 1
template<class T>
void BinaryTree<T>::postOrder(BinaryTreeNode<T>* root)
{
stack<BinaryTreeNode<T> * > nodeStack;
BinaryTreeNode<T> *pre = root, *pointer = root;
while (pointer)
{
//入栈过程
for (; pointer->LeftChild != NULL; pointer = pointer->LeftChild)
{
nodeStack.push(pointer);
}
//出栈过程
while (pointer != NULL && (pointer->RightChild == NULL || pointer->RightChild == pre))
//当前结点右孩子为空或右孩子刚被访问过,则访问该结点
{
visit(pointer);
pre = pointer;
if (nodeStack.empty())
return;
pointer = nodeStack.top();
nodeStack.pop();
}
//将当前结点压入栈中
nodeStack.push(pointer);
//将当前结点的右子树的根结点设为当前结点
pointer = pointer->RightChild;
}
}
删除以root为根结点的子树:
template<class T>
void BinaryTree<T>::deleteBinaryTree(BinaryTreeNode<T>* root)
{
if (root->LeftChild != NULL)
deleteBinaryTree(root->LeftChild);
if (root->RightChild != NULL)
deleteBinaryTree(root->RightChild);
delete root;
root = NULL;
}
根据前序和中序遍历表达式构造二叉树:
【思路】根据前序序列,找到根结点在中序序列中的位置,递归根结点的左子树序列和右子树序列。
template<class T>
BinaryTreeNode<T>* BinaryTree<T>::build_from_pre_and_in(char* preorder, char* inorder, int n)
{
if (n == )
return NULL;
char root_element = preorder[];
int i = ;
for( ;i < n;i ++)
{
if(root_element == inorder[i])
break;
}
BinaryTreeNode<T>* root = new BinaryTreeNode<T>;
root->element = root_element;
root->LeftChild = build_from_pre_and_in(preorder + , inorder, i);
root->RightChild = build_from_pre_and_in(preorder + i + , inorder + i + , n - i - );
return root;
}
根据后序和中序遍历表达式构造二叉树:
【思路】根据后序序列,找到根结点在中序序列中的位置,递归根结点的左子树序列和右子树序列。
template<class T>
BinaryTreeNode<T>* BinaryTree<T>::build_from_post_and_in(char* postorder, char* inorder, int m)
{
if (m == )
return NULL;
char root_element = postorder[m - ];
int i = ;
for( ;i < m;i ++)
{
if(root_element == inorder[i])
break;
}
BinaryTreeNode<T>* root = new BinaryTreeNode<T>;
root->element = root_element;
root->LeftChild = build_from_post_and_in(postorder, inorder, i);
root->RightChild = build_from_post_and_in(postorder+i, inorder + i+, m-i-);
return root;
}
测试函数:
int main()
{
BinaryTreeNode<char> *zero = ;
BinaryTreeNode<char> f('F'), g('G'), h('H');
BinaryTreeNode<char> d('D', &f, &g), e('E', zero, &h);
BinaryTreeNode<char> b('B', zero, &d), c('C', zero, &e);
BinaryTreeNode<char> a('A', &b, &c);
BinaryTree<char> Tree;
cout << "广度优先遍历为:" << endl;
Tree.breadthFirstOrder(&a);
cout << endl << "先序遍历为:" << endl;
Tree.preOrder(&a);
cout << endl << "中序遍历为:" << endl;
Tree.inOrder(&a);
cout << endl << "后序遍历为:" << endl;
Tree.postOrder(&a);
char *preorder = "ABDFGCEH";
char *inorder = "BFDGACEH";
char *postorder = "FGDBHECA";
int n = strlen(preorder);
int m = strlen(postorder);
BinaryTreeNode<char>* root1 = Tree.build_from_pre_and_in(preorder, inorder, n);
cout << endl << "先序中序构造后广度优先遍历为:" << endl;
Tree.breadthFirstOrder(root1);
BinaryTreeNode<char>* root2 = Tree.build_from_post_and_in(postorder, inorder, m);
cout << endl << "后序中序构造后广度优先遍历为:" << endl;
Tree.breadthFirstOrder(root2);
return ;
}
// 测试的二叉树
// A
// B C
// D E
// F G H
测试结果:
[BinaryTree] 二叉树类的实现的更多相关文章
- 数据结构实验6:C++实现二叉树类
实验6 学号: 姓名: 专业: 6.1 实验目的 掌握二叉树的动态链表存储结构及表示. 掌握二叉树的三种遍历算法(递归和非递归两类). 运用二叉树三种遍历的方法求解有关问题. 6 ...
- [BinaryTree] 二叉树常考知识点
1.二叉树第i层至多有2^(i-1)个结点(i>=1). 2.深度为k的二叉树上,至多含2^k-1个结点(k>=1) 3.n0 = n2 + 1(度) 4.满二叉树:深度为k且含有2^k- ...
- BinaryTree(二叉树) - 再谈二叉树
经过两天的研究,总算是完全梳理清二叉树的基本操作了,然后我又发现了一些对二叉树的新的认识. 先具体说说删除操作,前面在对二叉树的补充中,我说到了二叉树的删除操作可以有两种不同的代码编写方式(可点这里去 ...
- BinaryTree(二叉树)
我认为二叉树的递归实现体现了递归思想的一些重要性质,如果对递归的理解不够的话,想利用递归来实现是很费劲的(实际上我现在都还有些懵...),虽然会用,但一些地方不能弄清楚原因. 经过几天的学习,看了许多 ...
- 二叉树BinTree类定义
#include<iostream> using namespace std; template<class T> struct BinTreeNode{//二叉树结点类 T ...
- 表达式求值(二叉树方法/C++语言描述)(一)
使用二叉树对算数表达式(以下简称为表达式)进行求值,实质上是将表达式转换为二叉树,对其进行后序遍历,得到后缀表达式的同时可以求得表达式的值.转换和求值的过程也需要借助数据结构栈的帮助. 二叉树数据结构 ...
- K:二叉树
相关介绍: 二叉树是一种特殊的树,它的每个节点最多只有两棵子树,并且这两棵子树也是二叉树.由于二叉树中的两棵子树有左右之分,为此,二叉树是有序树. 二叉树的定义: 二叉树是由n(n>=0)个 ...
- 数据结构-二叉树(应用篇)-之二叉搜索树 C和C++的实现
一.概念 二叉搜索树(Binary Sort Tree/Binary Search Tree...),是二叉树的一种特殊扩展.也是一种动态查找表. 在二叉搜索树中,左子树上所有节点的均小于根节点,右子 ...
- Java实现二叉树的创建和遍历操作(有更新)
博主强烈建议跳过分割线前面的部分,直接看下文更新的那些即可. 最近在学习二叉树的相关知识,一开始真的是毫无头绪.本来学的是C++二叉树,但苦于编译器老是出故障,于是就转用Java来实现二叉树的操作.但 ...
随机推荐
- 两步搞定一台电脑同时开启多个tomcat
1. 修改tomcat中的某些参数,为了避免启动tomcat时出现冲突,编辑bin/startup.bat, 在文件第一行添加如下两行(必须第一行才有效) SET JAVA_HOME=C:\webso ...
- C#中访问私有成员--反射
首先我必须承认访问一个类的私有成员不是什么好做法.大家也都知道私有成员在外部是不能被访问的.而一个类中会存在很多私有成员:如私有字段.私有属性.私有方法.对于私有成员访问,可以套用下面这种非常好的方式 ...
- 全国各大城市Uber客服联系方式(电话、邮箱、微博)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 【费元星】crt 无法上传文件,总是显示盾牌表示-完美解决
将如下内容保存到文件中,已.bat 结尾 taskkill /f /im explorer.exeattrib -s -r -h "%userprofile%\AppData\Local\i ...
- 使用GC 初始化DG(将备份集复制到目标端再初始化)
概述 当前环境中有一个GC节点,一套RAC 11.2.0.4的数据库,一个已经使用GC进行在线初始化好的dg环境,需要模拟在远端使用rman备份集进行初始化DG的操作. 恢复环境 当前环境中 已经 ...
- KubeCon深度洞察 | KubeEdge开源首秀
以下内容根据华为云DJ在KubeCon Shanghai Demo Session演讲实录整理而成. KubeEdge Demo Show 11月15日上午Huawei宣布了KubeEdge项目开源, ...
- php常用几个数组的区别
本文主要介绍的php数组函数主要有:sort.rsort.asort.arsort.ksort.krsort 测试数据定义一个关联数组如下: $data=[ 'f'=>123, 'b'=> ...
- Selenium WebDriver(Python)API
1.通过示例介绍Selenium-WebDriver 一个简单的入门方法就是这个例子,它在Google上搜索术语“Cheese”,然后将结果页面的标题输出到控制台. java csharp pytho ...
- div布局方案整理
实际项目开发过程中遇到页面 DIV 左右布局的需求:左侧 DIV 固定宽度,右侧 DIV 自适应宽度,填充满剩余页面,由此引申出本文的几种解决方案 1 左侧 DIV 设置 float 属性为 left ...
- Python文件操作大全
Python 编程文件操作大全 文件打开模式 打开模式 执行操作 'r' 以只读方式打开文件(默认) 'w' 以写入的方式打开文件,会覆盖已存在的文件 'x' 如果文件已经存在,使用此模式打开将引 ...