- 合并两棵子树成一棵大树
- 判断一棵二叉树树是不是完全二叉树
- 判断一棵二叉树是不是满二叉树
- 计算一棵二叉树的高度
- 计算一棵二叉树的节点数
- 判断两棵二叉树是不是相同
- 前序遍历(递归和非递归实现)
- 中序遍历(递归和非递归实现)
- 后续遍历(递归和非递归实现)
/*********************************
*
* 使用指向节点实现二叉树的节点表示
* copyright @ : majin
* time : 2017 / 4 / 19
**********************************/
template<class T>
class BTreeNode{
public:
BTreeNode(T da){
data = da;
}
BTreeNode(T da, BTreeNode<T> *l, BTreeNode<T> *r){
data = da;
lChild = l;
rChild = r;
}
T data;
BTreeNode<T> *lChild;//指向左孩子
BTreeNode<T> *rChild;//指向右孩子
};
/*********************************
*
* 使用数组实现二叉树
* copyright @ : majin
* time : 2017 / 4 / 19
**********************************/
#include"BtreeNode.h"
#include<queue>
#include<stack>
template<class T>
int getNodeDeep(BTreeNode<T> *node);
template<class T>
bool isEqualHeight(BTreeNode<T> *node);
template<class T>
void copyNode(BTreeNode<T> *ynode, BTreeNode<T> *cnode);
template<class T>
class BTree{
public:
BTree(){ root = 0; }
bool makeTree(T value,BTree<T> &l,BTree<T> &r);//构造树 本节点值+左树根节点+右树根节点
bool isFullTree();//判断一棵树是不是满二叉树
bool isCompleteTree();//判断一棵树是不是完全二叉树
int getHeight(){//计算高度
return getNodeDeep(root);
}
bool isEmpty(){ return !root; }//看看树是不是空
bool isSample(const BTree<T> &tree);//确定两棵二叉树是否一样
bool deleteTree(); //删除整棵树
bool calc();//数学表达式树,计算表达式
bool getCalc();//数学表达式树,给出对应带括号的表达式
void preVisit(void(*visit)(BTreeNode<T>*node));//前序遍历
void inVisit(void(*visit)(BTreeNode<T>*node));//中序遍历
void postVisit(void(*visit)(BTreeNode<T>*node));//后续遍历
void levelVisit(void(*visit)(BTreeNode<T>*node));//层序遍历
void preNonDG(void(*visit)(BTreeNode<T>*node));//前序遍历的非递归
void inNonDG(void(*visit)(BTreeNode<T>*node));//中序遍历的非递归
void postNonDG(void(*visit)(BTreeNode<T>*node));//后序遍历的非递归
BTreeNode<T> *root;
};
//构造树 本节点值+左树根节点+右树根节点
template<class T>
bool BTree<T>::makeTree(T value, BTree<T> &l, BTree<T> &r){
try{
root = new BTreeNode<T>(value, l.root, r.root);
l.root = 0;
r.root = 0;
return true;
}
catch (...){
return false;
}
}
//得到一个节点的深度
template<class T>
int getNodeDeep(BTreeNode<T> *node){
if (!node){
return 0;
}
int ldeep = getNodeDeep(node->lChild);//得到左子树的深度
int rdeep = getNodeDeep(node->rChild);//得到右子树的深度
return ldeep > rdeep ? ldeep + 1 : rdeep + 1;
}
//判断一棵树是不是满二叉树
//一种方法(公式法):求出节点数n、二叉树的高度h,判断2^h-1=n
template <class T>
bool BTree<T>::isFullTree(){
return isEqualHeight(root);
}
//判断一个节点的两端是不是一样高
template<class T>
bool isEuqalHeight(BTreeNode<T> *node){
if (!node){
return true;
}
int ldeep = getNodeDeep(node->lChild);
int rdeep = getNodeDeep(node->rChild);
if (ldeep != rdeep){
return false;
}
else{
return isFull(node->lChild) && isFull(node->rChild);
}
}
//判断一棵树是不是完全二叉树
template<class T>
bool BTree<T>::isCompleteTree(){//判断一棵树是不是完全二叉树
queue<BTreeNode<T>*> q;
BTreeNode<T> *node;
q.push(root);
bool flag = false;
while (!q.empty()){
node = q.front();
q.pop();
if (node->lChild){
if (!flag){
q.push(node->lChild);
}
else{
return false;
}
}
else{
flag = true;
}
if (node->rChild){
if (!flag){
q.push(node->rChild);
}
else{
return false;
}
}
else{
flag = true;
}
}
return true;
}
//前序遍历节点
template<class T>
void preVisitNode(void(*visit)(BTreeNode<T>*node),BTreeNode<T> *node){
if (node){
visit(node);
preVisitNode(visit,node->lChild);
preVisitNode(visit,node->rChild);
}
}
//前序遍历
template<class T>
void BTree<T>::preVisit(void(*visit)(BTreeNode<T>*node)){
preVisitNode(visit,root);
}
//后序遍历节点
template<class T>
void postVisitNode(void(*visit)(BTreeNode<T>*node), BTreeNode<T> *node){
if (node){
postVisitNode(visit,node->lChild);
postVisitNode(visit,node->rChild);
visit(node);
}
}
//中序遍历节点
template<class T>
void inVisitNode(void(*visit)(BTreeNode<T>*node), BTreeNode<T> *node){
if (node){
inVisitNode(visit,node->lChild);
visit(node);
inVisitNode(visit,node->rChild);
}
}
template<class T>
void BTree<T>::inVisit(void(*visit)(BTreeNode<T>*node)){//中序遍历
inVisitNode(visit,root);
}
template<class T>
void BTree<T>::postVisit(void(*visit)(BTreeNode<T>*node)){//后续遍历
postVisitNode(visit,root);
}
template<class T>
void BTree<T>::levelVisit(void(*visit)(BTreeNode<T>*n)){//层序遍历
queue<BTreeNode<T>*> q;
q.push(root);
BTreeNode<T> *node;
while (!q.empty()){
node = q.front();
q.pop();
visit(node);
if (node->lChild){
q.push(node->lChild);
}
if (node->rChild){
q.push(node->rChild);
}
}
}
//判断两个节点是不是一样
template<class T>
bool isSampleNode(BTreeNode<T> *t1,BTreeNode<T> *t2){
if (t1 && t2){
//两个节点都不是空
if (t1->data != t2->data){
return false;
}
else{
return isSampleNode(t1->lChild,t2->lChild) && isSampleNode(t1->rChild,t2->rChild);
}
}
else if (!t1&&!t2){
//两个节点都是空
return true;
}
else{
//一个空,一个不是空,那么这两棵树一定不同
return false;
}
}
template<class T>
bool BTree<T>::isSample(const BTree<T> &tree){//确定两棵二叉树是否一样
return isSampleNode(root,tree.root);
}
template <class T>
void deleteNode(BTreeNode<T> *node){
delete node;
}
template<class T>
bool BTree<T>::deleteTree(){ //删除整棵树
try{
postVisit(deleteNode);
root = 0;
return true;
}
catch(...){
return false;
}
}
/***********************************************
* 各种非递归的遍历:遍历思想和我们手动遍历树是一样的,
* 前序:先遍历当前节点,再遍历左子树,左子树遍历完了再遍历右子树。注意到:最后遍历完左子树的节点优先遍历右子树。
* 中序:左-根-右。注意到:最后遍历完左子树的节点,优先被遍历,且节点被遍历完接着遍历右子树。
* 后续:左-右-根。这里笔者想到的是最笨但最易理解的方法:当一个节点的左右子树都被遍历完了,我们再遍历这个节点。(使用了类似Java中的包装的设计思想)
* copy right @ : majin
* time :2017 / 4 / 20
*********************************************/
//前序遍历的非递归
template<class T>
void BTree<T>::preNonDG(void(*visit)(BTreeNode<T>*node)){
stack<BTreeNode<T>*> s;
BTreeNode<T> *node = root;
do{
while (node){
visit(node);
s.push(node);
node = node->lChild;
}
//找到栈顶的节点,这个最后访问完左子树的节点,右子树优先访问
if (!s.empty()){
node = s.top();
s.pop();
node = node->rChild;
}
} while (node||!s.empty());
}
//中序遍历的非递归
template<class T>
void BTree<T>::inNonDG(void(*visit)(BTreeNode<T>*node)){
stack<BTreeNode<T>*> s;
BTreeNode<T> *node = root;
do{
while (node){
s.push(node);
node = node->lChild;
}
//找到栈顶的节点,最后访问完左子树的节点优先被访问,且接着访问右子树
if(!s.empty()){
node = s.top();
s.pop();
visit(node);
node = node->rChild;
}
} while (node || !s.empty());
}
//后序遍历的非递归
//根据后序遍历的特点:只有这个节点左孩子和右孩子都遍历完了,才会遍历这个节点,那么我们就记录下这个节点的左右孩子是不是被遍历过了
template<class T>
class BNodeLRVisited{
public:
BNodeLRVisited(BTreeNode<T> *n){
node = n; l = false; r = false;
}
BTreeNode<T> *node;
bool l;//记录左边孩子是不是被访问了
bool r;//同上
};
template<class T>
void BTree<T>::postNonDG(void(*visit)(BTreeNode<T>*node)){
stack<BNodeLRVisited<T>*> s;
BNodeLRVisited<T> *lrnode = new BNodeLRVisited<T>(root);
s.push(lrnode);
do{
if (lrnode && lrnode->l && lrnode->r){//lrnode节点的左右节点都被访问过,那么就要访问他了
visit(lrnode->node);
s.pop();
}
while (lrnode && !lrnode->l){//若左孩子没访问过,则访问;若访问过,则不需访问左孩子
lrnode->l = true;//改变lrnode的l标记
if (lrnode->node->lChild){//左孩子不空,左孩子入栈
lrnode = new BNodeLRVisited<T>(lrnode->node->lChild);//改变lrnode为左孩子(下面处理左孩子)
s.push(lrnode);
}
else{
lrnode = 0;//左孩子为空,退出遍历(break掉也行)
}
}
//找到栈顶的节点
if (!s.empty()){
lrnode = s.top();
if ( lrnode->node->rChild && !lrnode->r){//右节点存在且右节点没访问
lrnode->r = true;//改变r标记
lrnode = new BNodeLRVisited<T>(lrnode->node->rChild);//改变lrnode为右孩子(下面处理右孩子)
s.push(lrnode);
}else{//右孩子为空或右孩子被访问过
lrnode->r = true;//只需要改变r标记,不存在右节点进栈操作
}
}
} while (!s.empty());//栈中还有未访问的节点,继续
};
其他的实现方法
template<class T>
class BTree{
...
...
...
/**********************************************
* 上网查找
* copyright@:majin
* time:2017 / 4 / 20
************************************************/
//前序二:每次出栈一个,输出;右孩子进栈,左孩子进栈(注意顺序)
void preNonDG2(void(*visit)(BTreeNode<T>*node));//
//后序二:双指针,一个指向当前访问的节点,一个指向上一个访问的节点
//若上一个访问的节点是当前访问节点的右孩子。那么当前节点访问
void postNonDG2(void(*visit)(BTreeNode<T>*node));
//后序三:双栈法
void postNonDG3(void(*visit)(BTreeNode<T>*node));
...
...
}
//双指针
template<class T>
void BTree<T>::postNonDG2(void(*visit)(BTreeNode<T>*node)){
BTreeNode<T> *curr = root;;//当前要访问的节点
BTreeNode<T> *pre=0;//上一个访问的节点
stack<BTreeNode<T>*> s;
while (curr || !s.empty()){
while (curr){
s.push(curr);
curr = curr->lChild;
}
curr = s.top();
if (!curr->rChild || curr->rChild == pre){//当前节点没有右孩子或右孩子被访问过了,访问当前节点
visit(curr);
s.pop();
pre = curr;
curr = 0;
}
else{//当前节点有右孩子,访问右孩子
curr = curr->rChild;
}
}
}
//双栈
template<class T>
void BTree<T>::postNonDG3(void(*visit)(BTreeNode<T>*node)){
stack<BTreeNode<T>*> s1, s2;
BTreeNode<T>* curr = 0;//当前要访问的节点
s1.push(root);
while ( !s1.empty()){
curr = s1.top();
s1.pop();
s2.push(curr);
if (curr->lChild){
s1.push(curr->lChild);
}
if (curr->rChild){
s1.push(curr->rChild);
}
}
while (!s2.empty()){
curr = s2.top();
s2.pop();
visit(curr);
}
}