Bintree二叉树实现

二叉树的实现

学堂在线-数据结构-二叉树
环境: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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值