二叉树的实现
学堂在线-数据结构-二叉树
环境:DEV C++5.4.0。有课程资源但是无法运行,于是自己结合视频,敲了一边,函数名称尽量与视频中统一,有细微的不同。我自己写的部分注释掉了
二叉树的先序、中序、层次遍历栈(实现)和递归实现方法,孩子插入、删除、树的高度等。
二叉树的结点结构体头文件
实现了二叉树的父、孩子的插入,中序遍历下的直接后继等。
#ifndef _BINNODE_HPP
#define _BINNODE_HPP
#define BinNodePosi(T) BinNode<T>*
template<typename T>
struct BinNode
{
T data;
int height;//高度
BinNodePosi(T) parent;//父节点,子节点
BinNodePosi(T) lChild;
BinNodePosi(T) rChild;
BinNode();
BinNode(T const &e){data=e;lChild=NULL;rChild=NULL;}//只有值,无父无母
int size();//后代总数
BinNode(T const &e,BinNodePosi(T) parent){data=e;this->parent=parent;}//构造函数中,没有孩子
BinNodePosi(T) insertAsLC(T const &e);//插入,作为左孩子,
BinNodePosi(T) insertAsRC(T const &e);//插入,作为右孩子
BinNodePosi(T) succ();//中序遍历意义下,当前节点 的直接后继
};
template<typename T>
BinNodePosi(T) BinNode<T>::
insertAsLC(T const &e)
{
return lChild=new BinNode(e,this); //new
}
template<typename T>
BinNodePosi(T) BinNode<T>::
insertAsRC(T const &e)
{
return rChild=new BinNode(e,this);
}
/* my
template<typename T>
int BinNode<T>::size()
{
int rchildNum=0,lchildNum=0;
if(lChid!=NULL)
lchildNum=1+lChild->size();
if(rChid!=NULL)
rchildNum=1+rChild->size();
return rchildNum+rchildNum;//做后代,右后代; 什么都没有是0
}*/
template<typename T>
int BinNode<T>::size()
{
int s=1;//计入本身
if(lChild!=NULL)
s+=lChild->size();
if(rChild) s+=rChild->size();
return s;
}
#endif```
**二叉树的实现**
主要包括先序遍历、中续遍历、层次遍历,分别用栈和递归实现
```cpp
#include "BinNode.hpp"
#include "Stack.hpp"
#include "Queue.hpp"
#include "Algorithm.hpp"
#define stature(p) ((p)?(p)->height:-1)
template <typename T>class BinTree{
protected:
int _size;
BinNodePosi(T) _root;
virtual int updateHeight(BinNodePosi(T) x);//更新节点x的高度,虚,二叉搜索树高度定义不一样
void updateHeightAbove(BinNodePosi(T) x);//更新x及祖先的高度
public:
BinTree(BinNodePosi(T) root){_root=root;++_size;}//高度有疑问
BinTree(T const &e){_root->data=e;++_size;}//插入一棵子树,e为树根
int size() const{return _size;}//规模
bool empty() const{return !_root;} //判空
BinNodePosi(T) root() const {return _root;}//树根
BinNodePosi(T) insertAsRC(BinNodePosi(T) x, T const &e);
BinNodePosi(T) insertAsLC(BinNodePosi(T) x, T const &e);
BinNodePosi(T) firstChild();//长子
BinNodePosi(T) nextSibling();//兄弟
void insert(int r,T const &e);
T remove(int i);//删除第i个孩子(及其后代)
void traverse();//遍历
};
template <typename T>//更新节点x高度,具体规则因树不同而异
int BinTree<T>::updateHeight(BinNodePosi(T) x){
return x->height=1+max<int>(stature(x->lChild),stature(x->rChild));//??stature是binNode的方法?
} //此处采用常规二叉树规则
template<typename T>//更新v及其历代祖先的高度
void BinTree<T>::updateHeightAbove(BinNodePosi(T) x){
while(x)
{updateHeight(x);x=x->parent;}
}
template<typename T>
BinNodePosi(T) BinTree<T>::insertAsRC(BinNodePosi(T) x, T const &e)
{
//找到节点,这就涉及到遍历问题
++_size;x->insertAsRC(e); //x祖先的高度可能增加,其余节点必然不变
updateHeightAbove(x);//更新高度
return x->rChild;
}
template<typename T>
BinNodePosi(T) BinTree<T>::insertAsLC(BinNodePosi(T) x, T const &e)
{
//找到节点,这就涉及到遍历问题
++_size;x->insertAsLC(e); //x祖先的高度可能增加,其余节点必然不变
updateHeightAbove(x);//更新高度
return x->lChild;
}
template<typename T,typename VST>//先序遍历 栈
void travPre_I1(BinNodePosi(T) x,VST &visit)
{//用栈
Stack<BinNodePosi(T)> s;
if(x) s.push(x);//根节点入栈
while(!s.empty())//栈变空之前反复循环
{
x=s.pop();visit(x->data);//弹出并访问当前节点
if(x->rChild) s.push(x->rChild);//右遍历 ,视频中hasRChild 判断有无右孩子
if(x->lChild) s.push(x->lChild);//左遍历 ,视频中hasLChild 判断有无右孩子
}
}
//访问左侧链
template<typename T,typename VST>
void visitAlongLeftBranch(BinNodePosi(T) x,
Stack<BinNodePosi(T)> &s,//s的引用
VST &visit)
{
while(x){
visit(x->data);
//if(x->rChild) s.push(x->rChlid);//没有判断 ,文中没有判断,
s.push(x->rChild);//答:我认为值得,如果空的比较多,针对NULL还要进入访问左链函数
x=x->lChild;
}
}
template<typename T,typename VST>//栈实现先序遍历
void travPre_I2(BinNodePosi(T) x,VST &visit)
{
Stack< BinNodePosi(T)> s;
while(true)
{
visitAlongLeftBranch(x,s,visit);//访问左孩子链,遇到的右节点压入栈中
if(s.empty()) break;
x=s.pop();
}//#pop=#push=#visit=O(n)=分摊O(1);
}
/*
template<typename T,typename VST>//递归实现先序遍历
void travPre_I2(BinNodePosi(T) x,VST &visit)
{
if(!x) return;
visit(x->data);
//访问左子树
travPre_I2<T,VST>(x->lChild,visit);//尾递归,非常容易化解为迭代形式
travPre_I2<T,VST>(x->rChild,visit);
return ;//既无右子树,又左子树时停止。
}//递归不能做到足够小, */
//中序遍历
template<typename T,typename VST>//递归实现中序遍历
void traverseRecursionLDR(BinNodePosi(T) x,VST &visit)
{
if(x->lChild)//访问左子树
traverseRecursionLDR<T,VST>(x->lChild,visit);
else//没有左子树,才访问本节点
visit(x->data);
if(x->rChild)//访问右子树
traverseRecursionLDR<T,VST>(x->lChild,visit);
return ;//没有右子树返回
//PPT代码
/*if(!x) return;
traverseRecursionLDR(x->lChild,visit);
visit(x->data);
traverseRecursionLDR(x->rChild,visit);
*/
}//T(n)=T(a)+O(1)+T(n-a-1),改进?
//中序遍历
//遍历左侧链 ,不访问
template<typename T,typename VST>
void AlongLeftBranch(BinNodePosi(T) x,
Stack<BinNodePosi(T)> &s//s的引用
)
{
while(x){
//if(x->rChild) s.push(x->rChlid);//没有判断 ,文中没有判断,
if(x->rChild) s.push(x->rChild);//答:我认为值得,如果空的比较多,针对NULL还要进入访问左链函数
s.push(x);
x=x->lChild;
}
}
/*贪婪想法将所有遍历过的节点和其右节点压入栈中,无法判断那些可以使用造成死循环
template<typename T,typename VST>//递归实现中序遍历 未测试
void traverseLDR(BinNodePosi(T) x,VST &visit)
{
Stack< BinNodePosi(T)> s;
//s.push(x);
while(true)
{
AlongLeftBranch<T,VST>(s.top(),s);//访问左孩子链,遇到的右节点先压入栈中
x=s.pop();
visit(x->data);
if(s.empty()) break;
}//#pop=#push=#visit=O(n)=分摊O(1);
}//T(n)=T(a)+O(1)+T(n-a-1),改进? */
template<typename T>
static void goAlongLeftBranch(BinNodePosi(T) x,Stack<BinNodePosi(T)> &s)
{ while(x){ s.push(x);x=x->lChild; }}
template<typename T,typename VST>
void travIn_I1(BinNodePosi(T) x,VST &visit)
{
Stack< BinNodePosi(T)> s;
while(true)
{
goAlongLeftBranch(x,s);
if(s.empty()) break;
x=s.pop();
visit(x->data);
x=x->rChild;
}
}//时间? O(n)线性,常系数而言优于递归。 分摊分析
//层次遍历
//队列:在遍历父层时将孩子队列放入
template <typename T,typename VST>
void travLevel(BinNodePosi(T) x,VST &visit)
{
Queue<BinNodePosi(T)> q;
q.enqueue(x);
while(!q.empty())
{
x=q.dequeue();
visit(x->data);
//将x的孩子入队
if(x->lChild) q.enqueue(x->lChild);
if(x->rChild) q.enqueue(x->rChild);
}
}
测试代码
#include <iostream>
#include "BinTree.hpp"
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
template <typename T>
void print(T &e)
{
std::cout<<e<<" ";
}
int main(int argc, char *argv[]) {
BinNode<int> bn(1);
BinNode<int> bn3(3);
BinNode<int> bn4(4);
BinNode<int> bn5(5);
BinNode<int> bn6(6);
BinNodePosi(int) root=&bn;
BinNodePosi(int) bnt;
BinTree<int> bintree(root);
//std::cout<<bn.size()<<std::endl;
//先序遍历测试
/*bnt=bn.insertAsLC(2);
bn.insertAsRC(7);
bnt->insertAsRC(6);
bnt=bnt->insertAsLC(3);
bnt->insertAsRC(5);
bnt->insertAsLC(4);*/
//travPre_I2<int>(root,print<int>);//为何这里没有模板参数
//中序遍历测试
/* bnt=bn4.insertAsLC(2);
bnt->insertAsRC(3);
bnt->insertAsLC(1);
bnt=bn4.insertAsRC(6);
bnt->insertAsRC(7);
bnt->insertAsLC(5);
// traverseLDR(&bn4,print<int>);//错误的函数
travIn_I1(&bn4,print<int>);*/
//traverseRecursionLDR<int>(&bn4,print<int>);
//层次遍历实现
bnt=bn.insertAsLC(2);
bnt->insertAsLC(4);
bnt->insertAsRC(5);
bnt=bn.insertAsRC(3);
bnt->insertAsLC(6);
bnt->insertAsRC(7);
travLevel(&bn,print<int>);
return 0;
}
三种方法的测试结果都是:
1 2 3 4 5 6 7