二叉树结点的抽象数据类型:

 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] 二叉树类的实现的更多相关文章

  1. 数据结构实验6:C++实现二叉树类

    实验6 学号:     姓名:      专业:   6.1 实验目的 掌握二叉树的动态链表存储结构及表示. 掌握二叉树的三种遍历算法(递归和非递归两类). 运用二叉树三种遍历的方法求解有关问题. 6 ...

  2. [BinaryTree] 二叉树常考知识点

    1.二叉树第i层至多有2^(i-1)个结点(i>=1). 2.深度为k的二叉树上,至多含2^k-1个结点(k>=1) 3.n0 = n2 + 1(度) 4.满二叉树:深度为k且含有2^k- ...

  3. BinaryTree(二叉树) - 再谈二叉树

    经过两天的研究,总算是完全梳理清二叉树的基本操作了,然后我又发现了一些对二叉树的新的认识. 先具体说说删除操作,前面在对二叉树的补充中,我说到了二叉树的删除操作可以有两种不同的代码编写方式(可点这里去 ...

  4. BinaryTree(二叉树)

    我认为二叉树的递归实现体现了递归思想的一些重要性质,如果对递归的理解不够的话,想利用递归来实现是很费劲的(实际上我现在都还有些懵...),虽然会用,但一些地方不能弄清楚原因. 经过几天的学习,看了许多 ...

  5. 二叉树BinTree类定义

    #include<iostream> using namespace std; template<class T> struct BinTreeNode{//二叉树结点类 T ...

  6. 表达式求值(二叉树方法/C++语言描述)(一)

    使用二叉树对算数表达式(以下简称为表达式)进行求值,实质上是将表达式转换为二叉树,对其进行后序遍历,得到后缀表达式的同时可以求得表达式的值.转换和求值的过程也需要借助数据结构栈的帮助. 二叉树数据结构 ...

  7. K:二叉树

    相关介绍:  二叉树是一种特殊的树,它的每个节点最多只有两棵子树,并且这两棵子树也是二叉树.由于二叉树中的两棵子树有左右之分,为此,二叉树是有序树. 二叉树的定义:  二叉树是由n(n>=0)个 ...

  8. 数据结构-二叉树(应用篇)-之二叉搜索树 C和C++的实现

    一.概念 二叉搜索树(Binary Sort Tree/Binary Search Tree...),是二叉树的一种特殊扩展.也是一种动态查找表. 在二叉搜索树中,左子树上所有节点的均小于根节点,右子 ...

  9. Java实现二叉树的创建和遍历操作(有更新)

    博主强烈建议跳过分割线前面的部分,直接看下文更新的那些即可. 最近在学习二叉树的相关知识,一开始真的是毫无头绪.本来学的是C++二叉树,但苦于编译器老是出故障,于是就转用Java来实现二叉树的操作.但 ...

随机推荐

  1. C语言基础——链表的相关操作

    1 #include <stdio.h> #include <malloc.h> #include <string.h> #include <math.h&g ...

  2. P2P通讯

    转载: http://www.cnblogs.com/pannengzhi/p/4800526.html http://blog.csdn.net/lee353086/article/details/ ...

  3. Tips & Tricks Learned Releasing an Hybrid App Using Steroids.js

    http://marcgg.com/blog/2014/04/09/phonegap-steroids-hybrid-native-app-tips/

  4. Solr第二讲——SolrJ客户端的使用与案例

    一.Solrj的使用 1.什么是Solrj solrj是访问Solr服务的java客户端(就像通过jedis操作redis一样),提供索引和搜索的请求方法,SolrJ通常在嵌入在业务系统中,通过Sol ...

  5. 青岛Uber司机奖励政策(8月31号~9月6号)

    本周的奖励规则如下,请各位司机朋友按照自己的情况查询. 人民优步(People’s Uber) 滴滴快车单单2.5倍,注册地址:http://www.udache.com/如何注册Uber司机(全国版 ...

  6. 单例模式之pymysql运用实例

    何为单例? 简单介绍一下下:单例是个什么鬼东西!!!! 单例模式含义] 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而 ...

  7. apache+php开发环境搭建步骤

    apache 卸载apache服务命令:sc delete apache 1.在D盘下面新建文件夹php7 2.解压apache到php7文件夹下面 3.修改配置文件 4.安装apache服务C:\w ...

  8. C 计算数字的位数循环

    #include <stdio.h> int main(int argc, char **argv) { // int x; int n=0; scanf("%d",& ...

  9. HTML+JS = 网站注册界面源代码

    本注册页面未设置编码方式和兼容性,已测试,在Chrome浏览器显示正常 <!DOCTYPE html> <html> <head> <title>注册页 ...

  10. js for循环实例

    1.求1-100的寄数和? //2.奇数求和 var ppt=0 for(var i=1;i<=100;i+=2){ ppt+=i } 2.求1-100的偶数和 var num=0 for(va ...