/*
第二次上机
题目:二叉树相关算法的实验验证
[实验目的]
验证二叉树的链接存储结构及其上的基本操作。
[实验内容及要求]
1、 定义链接存储的二叉树类。 √完成
2、 实验验证如下算法的正确性、各种功能及指标:
1)创建一棵二叉树,并对其初始化; √完成
2)先根、中根、后根遍历二叉树; √完成
3)在二叉树中搜索给定结点的父结点; √完成
4)搜索二叉树中符合数据域条件的结点; √完成
5)从二叉树中删除给定结点及其左右子树。 √完成
3、 为便于观察程序的运行结果,设计的输出函数能在输出设备上以图形或表格或其它直观的形式输出计算结果。 √完成!!
例如将二叉树输出为
1
/
2 3
/ /
5 6 7 8
4、 测试程序时,对所有输入变量取遍各种有代表性的值。 √完成
5、 为了增强程序的可读性,程序中要有适当的注释。 √完成
*/
#ifndef BINTREE_
#define BINTREE_
#include "AStack.h"
#include "AQueue.h"
#include <string>
usingnamespacestd;
//AStack.h和AQueue.h还有本文件大部分代码都是教科书《数据结构》附录里的
//结点声明
template<typenameT>classBinTreeNode{
private:
BinTreeNode<T>*left,*right;//左右子树链接
Tdata;//数据域
intx=0;//输出时的相对位置,在中根遍历时设置
intoffset=-1;//距最左边的偏移量;即坐标。
intlw=-1;//左子宽度
intw=-1;//数据宽度
intrw=-1;//右子宽度
public:
//构造函数
BinTreeNode(constT&item,BinTreeNode<T>*lptr=NULL,BinTreeNode<T>*rptr=NULL):data(item),left(lptr),right(rptr){}
BinTreeNode<T>*GetLeft(void)const{returnleft;} //返回左结点
voidSetLeft(BinTreeNode<T>*l){left=l;} //设置左结点
BinTreeNode<T>*GetRight(void)const{returnright;} //返回右结点
voidSetRight(BinTreeNode<T>*r){right=r;} //设置右结点
T&GetData(){returndata;} //返回数据域
voidSetData(constT&item){data=item;} //设置数据域
int&RgetX(){returnx;}
int&RgetOffset(){returnoffset;}
int SetLw();
int GetLw();
int SetW();
int GetW();
int SetRw();
int GetRw();
//int DataWidth();
//设置数据域宽度
intDataWidth(int_data){
intlen=0;
(_data<0)?len=1:len=0;//负数多个负号
do{
len++;
_data/=10;
}while(_data);
returnlen;
}
intDataWidth(char_data){return1;}
intDataWidth(constchar*_data){returnstd::strlen(_data);}
intDataWidth(std::string_data){return_data.length();}
};
template<typenameT>intBinTreeNode<T>::GetLw(){
if(lw==-1)lw=SetLw();
returnlw;
}
template<typenameT>intBinTreeNode<T>::SetLw(){
if(left!=NULL){
// _a
// |
// _b
//|
//c
//a的左边宽度=b左+b+b右。但 b+b右 < 2 时应 取2
lw=(left->GetW()+left->GetRw())>2?(left->GetW()+left->GetRw()):2;
lw+=left->GetLw();
}
elselw=0;
returnlw;
}
template<typenameT>intBinTreeNode<T>::GetRw(){
if(rw==-1)rw=SetRw();
returnrw;
}
template<typenameT>intBinTreeNode<T>::SetRw(){
if(right!=NULL){
// a_
// |
// b
//a右宽=b左+b+b右。但 b左+b <2 时应取2
rw=(right->GetLw()+right->GetW())>2?(right->GetLw()+right->GetW()):2;
rw+=right->GetRw();
}
elserw=0;
returnrw;
}
template<typenameT>intBinTreeNode<T>::GetW(){
if(w==-1)w=SetW();
returnw;
}
template<typenameT>intBinTreeNode<T>::SetW(){
w=DataWidth(data);
returnw;
}
//1、 定义链接存储的二叉树类。
//二叉树类-连接存储结构
template<typenameT>classBinTree{
private:
BinTreeNode<T>*root; //根节点
Tstop; //构造二叉树时的输入结束符,即输入stop则停止输入
public:
BinTree(BinTreeNode<T>*t=NULL):root(t){} //构造函数
virtual~BinTree(){Del(root);} //析构函数,删除整棵二叉树,Del()函数稍后定义
//在以t为根的树中搜索p的父节点
BinTreeNode<T>*Father(BinTreeNode<T>*t,BinTreeNode<T>*p);
//在以t为根节点的树中查找data域值为item的结点
BinTreeNode<T>*Find(BinTreeNode<T>*t,constT&item)const;
//删除t子树(包括t结点本身)
voidDelSubtree(BinTreeNode<T>*t);
voidDel(BinTreeNode<T>*t);
voidPreOrder(BinTreeNode<T>*t)const; //先根遍历 并输出该树
voidInOrder(BinTreeNode<T>*t)const; //中根遍历 并输出该树
voidPostOrder(BinTreeNode<T>*t)const; //后根遍历 并输出该树
voidLevelOrder(BinTreeNode<T>*t)const; //层次遍历 并输出该树
voidNorecPreOrder(BinTreeNode<T>*t)const; //非递归先根遍历 并输出该树
voidNorecInOrder(BinTreeNode<T>*t,constintout=1)const; //非递归中根遍历并计算中根序下各结点X坐标,如果out为真则输出该树
voidNorecPostOrder(BinTreeNode<T>*t)const; //非递归后跟遍历 并输出该树
voidSetX(){NorecInOrder(root,0);}
voidCreatBinTree(Ttostop); //创建二叉树
BinTreeNode<T>*Creat();
BinTreeNode<T>*CopyTree(BinTreeNode<T>*t); //复制二叉树t
//输出二叉树!
voidDisplay(BinTreeNode<T>*t,//要输出的树
constchar*msg=NULL,//msg:可选的提示信息,(应以结尾(用cout不需要也可以))
constintoffset=0);//offset:可选整体偏移量,
//其他操作
BinTreeNode<T>*GetRoot(){returnroot;}
voidSetRoot(BinTreeNode<T>*t){root=t;}
TGetStop(){returnstop;}
voidSetStop(Ttostop){stop=tostop;}
intIsEmpty(){returnroot==NULL?1:0;}
};
//中根遍历-非递归
template<typenameT>voidBinTree<T>::NorecInOrder(BinTreeNode<T>*t,constintout=1)const{
if(t==NULL)return;
t->SetLw();t->SetW();t->SetRw();
AStack<BinTreeNode<T>*>s;
inti=0,z=0;
BinTreeNode<T>*p=t;
while(p->GetLeft()!=NULL){p=p->GetLeft();}
while(t!=NULL||!s.IsEmpty()){
while(t!=NULL){
s.Push(t);
t=t->GetLeft();
}
if(s.IsEmpty())return;
i++;
s.Pop(t);
if(p==t){t->RgetOffset()=0;}//第一个结点
else{
if(t->GetLeft()==p){//t是前一个节点p的父结点
/*
* _2 __1
*| |
*1 100
*/
z=p->GetW();
if(z<2)z=2;
t->RgetOffset()=p->RgetOffset()+z;
//cout << p->RgetOffset() << "(p.o)" << p->GetW() << "(p.W) " << z << "n";
}
elseif(p->GetRight()==t){//t是前一个节点p的子节点
/*
*012 01234
*2_ 200_
* | |
* 3 233
*/
t->RgetOffset()=p->RgetOffset()+p->GetW()+1;
}
else{//t和前一个结点p不是父子关系
/*
* ____1 100___
*| |
*3_ __3
* | |
* 200 200
*/
t->RgetOffset()=p->RgetOffset()+p->GetW();
}
p=t;
//cout << p->RgetOffset() << ") ";
}//t不是第一个结点
if(out){std::cout<<t->GetData()<<" ";}
t->RgetX()=i;
t=t->GetRight();
}
}
//层次遍历 (使用了队列AQueue类)
template<typenameT>voidBinTree<T>::LevelOrder(BinTreeNode<T>*t)const{
/*
//书上的,一次全部输出
if (t == NULL)return;
BinTreeNode<T> *p;
AQueue<BinTreeNode<T>*> q;
q.QInsert(t);
while (!q.isEmpty()){
q.QDelete(p);
std::cout << p->GetData() << " ";
if (p->GetLeft() != NULL)q.QInsert(p->GetLeft());
if (p->GetRight() != NULL)q.QInsert(p->GetRight());
}
*/
if(t==NULL)return;
BinTreeNode<T>*p=t,*end=newBinTreeNode<T>(stop);
AQueue<BinTreeNode<T>*>q;
q.QInsert(p);
q.QInsert(end);
while(true)
{
q.QDelete(p);
if(q.isEmpty())break;
if(p!=end){std::cout<<p->GetData()<<" ";}
else{std::cout<<"n";q.QInsert(end);}
if(p->GetLeft()!=NULL){q.QInsert(p->GetLeft());}
if(p->GetRight()!=NULL){q.QInsert(p->GetRight());}
}
std::cout<<"n";
deletep;
//delete end;
}
//输出二叉树!!
template<typenameT>voidBinTree<T>::Display(BinTreeNode<T>*t,constchar*msg,constintoffset){
if(msg){cout<<msg<<"n";}
//cout << "DDDDDDDDDDDDDDDDDDDDDDDDDDDDn";//////////////////////////////////////////////////////////////
if(NULL==t)return;
NorecInOrder(t,0);//设置每个结点的宽度、坐标。
BinTreeNode<T>*p=t,*end=newBinTreeNode<T>(stop);
AQueue<BinTreeNode<T>*>q;
q.QInsert(p);q.QInsert(end);
intj=0;//光标的当前坐标
for(inti=0;i<offset;i++){cout<<" ";}
while(true)
{
if(q.QFront()==end){cout<<"n";break;}
//数据层
while(true)
{
q.QDelete(p);
q.QInsert(p);
//cout << p->GetData() << "(data)n";
if(p==end){
cout<<"n";
for(inti=0;i<offset;i++){cout<<" ";}
j=0;
break;}
if(p->GetLeft()!=NULL){
for(;j<=p->GetLeft()->RgetOffset();j++){cout<<" ";}
for(;j<p->RgetOffset();j++){cout<<"_";}
}
else{
for(;j<p->RgetOffset();j++){cout<<" ";}
}
cout<<p->GetData();j+=p->GetW();
if(p->GetRight()!=NULL){
for(;j<p->GetRight()->RgetOffset();j++){cout<<"_";}
}
}//数据层
//“|”连接层
while(true)
{
q.QDelete(p);
if(p==end){
cout<<"n";
for(inti=0;i<offset;i++){cout<<" ";}
j=0;
q.QInsert(end);
break;
}
if(p->GetLeft()!=NULL){
for(;j<p->GetLeft()->RgetOffset();j++){cout<<" ";}
cout<<"|";j++;//半角管道符
//cout << "│"; j+=3;//全角制表符-不好控制
q.QInsert(p->GetLeft());}
if(p->GetRight()!=NULL){
for(;j<p->GetRight()->RgetOffset();j++){cout<<" ";}
cout<<"|";j++;//半角管道符
//cout << "│"; j+=3;//全角制表符-不好控制
q.QInsert(p->GetRight());
}
}//连接层
}//层次遍历输出
}//void
//1)创建一棵二叉树,并对其初始化;
//调用时必须指明tostop值,然后本函数调用Creat。
template<typenameT>voidBinTree<T>::CreatBinTree(Ttostop){
SetStop(tostop);
root=Creat();
}
//数据在这个函数输入,以设置的stop代替空结点,先根次序输入。
template<typenameT>BinTreeNode<T>*BinTree<T>::Creat(){
BinTreeNode<T>*t,*t1,*t2;
Titem;
cin>>item;
if(item==stop){t=NULL;returnt;}
else{
if(!(t=newBinTreeNode<T>(item,NULL,NULL)))returnNULL;
t1=Creat();
t->SetLeft(t1);
t2=Creat();
t->SetRight(t2);
returnt;
}
}
//2)先根、中根、后根遍历二叉树;
//先根遍历-递归
template<typenameT>voidBinTree<T>::PreOrder(BinTreeNode<T>*t)const{
if(t!=NULL){
std::cout<<t->GetData()<<" ";
PreOrder(t->GetLeft());
PreOrder(t->GetRight());
}
}
//中根遍历-递归
template<typenameT>voidBinTree<T>::InOrder(BinTreeNode<T>*t)const{
if(t!=NULL){
InOrder(t->GetLeft());
std::cout<<t->GetData()<<" ";
InOrder(t->GetRight());
}
}
//后根遍历-递归
template<typenameT>voidBinTree<T>::PostOrder(BinTreeNode<T>*t)const{
if(t!=NULL){
PostOrder(t->GetLeft());
PostOrder(t->GetRight());
std::cout<<t->GetData()<<" ";
}
}
//3)在二叉树中搜索给定结点的父结点;
template<typenameT>BinTreeNode<T>*BinTree<T>::Father(BinTreeNode<T>*t,BinTreeNode<T>*p){
BinTreeNode<T>*q;
if(t==NULL||p==NULL)returnNULL; //若其中之一为空返回空
if(t->GetLeft()==p||t->GetRight()==p)returnt; //若t即为p父节点,直接返回t
//在左右子树中寻找(递归)
if((q=Father(t->GetLeft(),p))!=NULL)returnq;
elsereturnFather(t->GetRight(),p);
}
//4)搜索二叉树中符合数据域条件的结点;
template<typenameT>BinTreeNode<T>*BinTree<T>::Find(BinTreeNode<T>*t,constT&item)const{
BinTreeNode<T>*p,*q;
if(NULL==t)returnNULL;
if(t->GetData()==item)returnt;
if((p=Find(t->GetLeft(),item))!=NULL)returnp;
elsereturnq=Find(t->GetRight(),item);
}
//5)从二叉树中删除给定结点及其左右子树。
//删除子树t
//需要用到Father(),Del(),BinTreeNode.
template<typenameT>voidBinTree<T>::DelSubtree(BinTreeNode<T>*t){
if(NULL==t)return;
if(t==root){
Del(t);
root=NULL;
return;
}
BinTreeNode<T>*p,*q;
p=t;
q=Father(root,p);
if(q){
if(q->GetLeft()==p)q->SetLeft(NULL);
if(q->GetRight()==p)q->SetRight(NULL);
}
Del(p);
}
//删除树t
template<typenameT>voidBinTree<T>::Del(BinTreeNode<T>*t){
if(t!=NULL){
Del(t->GetLeft());
Del(t->GetRight());
deletet;
}
}
#endif