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

 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. #if、#if defined 的使用

    #if的使用 if 后面接的是表达式 #if a==1 code -- #endif 如果#if后面的表达式能成立,就会把#if和#endif之间的代码编译进去 #if defined的使用 #if ...

  2. xargs命令的使用过程中一个小领悟:管道与xargs的差别

    对xargs的使用总是比较模糊,大概的理解为:通道中,上一个命令的标准输出逐行作为下一个命令的参数 例如 find /var/temp* | xargs rm -r 功效:找出/var/中所有temp ...

  3. Redis的n种妙用,不仅仅是缓存

    redis是键值对的数据库,常用的五种数据类型为字符串类型(string),散列类型(hash),列表类型(list),集合类型(set),有序集合类型(zset) Redis用作缓存,主要两个用途: ...

  4. 成都Uber优步司机奖励政策(3月31日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  5. LeetCode:35. Search Insert Position(Easy)

    1. 原题链接 https://leetcode.com/problems/search-insert-position/description/ 2. 题目要求 给定一个已经排好序的数组和一个目标值 ...

  6. ORB-SLAM(十二)优化

    ORB-SLAM中优化使用g2o库,先复习一下g2o的用法,上类图 其中SparseOptimizer就是我们需要维护的优化求解器,他是一个优化图,也是一个超图(包含若干顶点和一元二元多元边),怎样定 ...

  7. centos7下安装mysql8.0.12及设置权限

    一.mysql版本介绍 mysql的官网为:https://www.mysql.com/ 在官网上可以看到多个版本,主要版本如下, 1.MySQL Community Server 社区版本,开源免费 ...

  8. 微信小程序学习笔记(1)- 按钮触发的函数的定义以及不同页面之间的数据传递

    <view class='item' bindtap='onCountryTab' data-idx='4'> 1)bindtap属性用来设置控件需要绑定的函数,函数用单引号括起来:. 2 ...

  9. ElasticSearch-Java-low-level-rest-client官方文档翻译

    人肉翻译,非谷歌机翻,部分地方添加了个人的理解,并做了分割,如有错误请在评论指出.转载请指明原链接,尊重个人劳动成果.        High-Level-Rest-Client基于Low-Level ...

  10. 微信小程序—day03

    昨日问题 接着上一篇,昨天遇到的scroll-view组件不能滚动的问题. 今天经过调试,发现是由于:图片的实际宽高,大于给image设定的宽高导致的. 解决办法: 减小图片的实际宽高,使之小于ima ...