您的位置:首页 > 理论基础 > 数据结构算法

【数据结构】二叉树的简单操作及简单应用

2016-12-03 22:27 561 查看
简介:

二叉树的应用十分广泛。根据二叉树的前序序列和中序序列,可以构造出二叉树。构造方法可以采用递归和非递归。二叉树的遍历通常有四种方法,分别是前序遍历,中序遍历,后序遍历,层序遍历。其中,前序,中序,后序又有递归和非递归两种写法。求最近公共祖先的方法同样有很多。这里选择了一种时间、空间复杂度较低的方法。

本文主要分为以下几个部分:

递归与非递归建树

不同方式的遍历

寻找最近公共父节点

正文:

建树

递归

每次搜到中序序列中当前节点的位置,以此位置为界,将中序序列中的区间一分为二,然后分别传给左、右子树进行递归。

非递归

栈中存储当前节点的子树区间(L与R)以及他们的父节点(即当前节点)。
每次循环,将栈顶元素出栈,先找到当前元素在中序序列中的位置,然后根据对应的区间,将左右子树的区间入栈。
直到栈空为止。
注意:
应该先让右子树入栈,再让左子树入栈,保证顺序的正确。

遍历

递归

递归遍历比较简单,在每一层分别递归访问左子树右子树,然后根据前序,中序,后序的不同,调整输出语句的位置即可。

非递归

非递归主要是用栈实现,根据遍历顺序的不同,实现方法有所不同。

前序

每次访问栈顶元素,先把栈顶元素输出并弹出,然后将左右子树分别入栈,直到栈空为止。
注意先让右子树进栈,再让左子树进栈,保证输出顺序的正确。

中序

每次访问栈顶元素,先判断是否满足输出条件:是否是叶子节点、是否是已经访问过的父节点。满足则输出、弹出。
不满足则弹出栈顶(父节点),右子树入栈,原栈顶(即父节点)入栈,左子树入栈。
直到栈空为止。

后序

如果在前序遍历中,访问完父节点后,先访问右子树,在访问左子树,得到的序列正是后续访问的逆序列。
所以用一个数组储存按上述方法遍历得到的序列,最后逆向输出即可。

层序

利用队列,访问到队头元素,把它的左右子树放到对位,直到队列为空。

寻找最近公共父节点

建一个长度大于树的高度的数组,用来存储由根到目标节点的各个节点的访问情况。

然后从任一个目标节点开始向上访问,直到根节点,一路上所有的节点都标记位“已访问”。这样,已经标记过的便是此节点的父节点之一。

最后从另一个目标节点开始向上访问,一直到找到已经访问过的节点,此节点既是此节点的父节点,又是第一个节点的父节点,因此是两个节点的公共父节点。又因为第一个出现,所以是两个节点的最近公共祖先。

空间复杂度 :小于树的高度。

时间复杂度:小于2*树的高度。
CODE:

#include<iostream>
#define N n+1
using namespace std;
typedef struct Tree
{
int data;
int father,lson,rson;
};
Tree *T;
int n;
int *preord;	//存放前序表达序列
int *midord;	//存放中序表达序列
int now;		//递归所用计数器

void find(int f1,int f2);	//【042-073】 寻找最近公共祖先(实现函数)
void lca();					//【074-085】 寻找最近公共祖先(主函数)

void oudlr1(int n);			//【086-092】 前序递归
void oudlr2();				//【093-115】 前序非递归
void ouldr1(int n);			//【116-122】 中序递归
void ouldr2();				//【123-161】 中序非递归
void oulrd1(int n);			//【162-168】 后序递归
void oulrd2();				//【169-194】 后序非递归
void floor();				//【195-207】 层序
void putit(int head);		//【208-251】 输出主函数

int make1(int l,int r);		//【252-289】 递归建树
void make2();				//【290-351】 非递归建树
void build();				//【352-366】 建树总菜单

void init(int n,int ord[]);	//【367-371】 输入序列
void start();				//【372-388】 开始函数

int main()
{
start();
build();
putit(1);
lca();
return 0;
}
void find(int f1,int f2)
{
int bo
;
int ff1,ff2;
T[1].father=1;
for (int i=0;i<=n;i++)
{
if (T[i].data==f1)
{
ff1=i;
}
if (T[i].data==f2)
{
ff2=i;
}
}
for (int i=0;i<=n;i++)
{
bo[i]=0;
}
while (ff1!=1)
{
bo[ff1]=1;
ff1=T[ff1].father;
}
while (bo[T[ff2].father]==0 && ff2!=1)
{
ff2=T[ff2].father;
}
cout<<"lca:"<<T[T[ff2].father].data<<endl;

}
void lca()
{
int f1,f2;
cout<<endl<<endl<<"输入要查找的两个节点,0 0 结束"<<endl;
cin>>f1>>f2;
while (!(f1==f2&&f1==0))
{
find(f1,f2);
cin>>f1>>f2;
}
return;
}
void oudlr1(int n)
{
cout<<T
.data<<" ";
if (T
.lson!=-1) oudlr1(T
.lson);
if (T
.rson!=-1) oudlr1(T
.rson);
return;
}
void oudlr2()
{
int sta
;
int noww=1;
sta[noww]=1;
while (noww>0)
{
int stn=sta[noww];
noww--;
cout<<T[stn].data<<" ";
if (T[stn].rson!=-1)
{
noww++;
sta[noww]=T[stn].rson;
}
if (T[stn].lson!=-1)
{
noww++;
sta[noww]=T[stn].lson;
}
}
return;
}
void ouldr1(int n)
{
if (T
.lson!=-1) ouldr1(T
.lson);
cout<<T
.data<<" ";
if (T
.rson!=-1) ouldr1(T
.rson);
return;
}
void ouldr2()
{
int boo
;
int sta
;
int now=1;
sta[1]=1;
for (int i=0;i<N;i++) boo[i]=0;
while (now>0)
{
if (boo[sta[now]]==1)
{
cout<<T[sta[now]].data<<" ";
now--;
continue;
}

boo[sta[now]]=1;
int nn=sta[now];
if (T[nn].lson==-1 && T[nn].rson==-1)
{
cout<<T[nn].data<<" ";
now--;
continue;
}
if (T[nn].rson!=-1)
{
sta[now]=T[nn].rson;
now++;
sta[now]=nn;
}
nn=sta[now];
if (T[nn].lson!=-1)
{
now++;
sta[now]=T[nn].lson;
}
}
return;
}
void oulrd1(int n)
{
if (T
.lson!=-1) oulrd1(T
.lson);
if (T
.rson!=-1) oulrd1(T
.rson);
cout<<T
.data<<" ";
return;
}
void oulrd2()
{
int sta
;
int sta1
;
int noww=1,s=1;
sta[noww]=1;
while (noww>0)
{
int stn=sta[noww];
noww--;
sta1[s++]=T[stn].data;
if (T[stn].lson!=-1)
{
noww++;
sta[noww]=T[stn].lson;
}
if (T[stn].rson!=-1)
{
noww++;
sta[noww]=T[stn].rson;
}
}
for (int i=0;i<n;i++)
cout<<sta1[n-i]<<" ";
return;
}
void floor()
{
int que
;
int l=1,r=2;
que[1]=1;
while ((l<=r)&& (l<N))
{
if(T[que[l]].lson!=-1) que[r++]=T[que[l]].lson;
if(T[que[l]].rson!=-1) que[r++]=T[que[l]].rson;
cout<<T[que[l]].data<<" ";
l++;
}
}
void putit(int head)
{
cout<<endl<<"选择遍历方式:1、前序 2、中序 3、后序 4、层序"<<endl;
int choose;
cin>>choose;
if (choose==1)
{
cout<<endl<<"前序遍历:"<<endl;
cout<<"选择递归(0)非递归(1)"<<endl;
int ch;
cin>>ch;
if (ch==0)
oudlr1(head);
else
oudlr2();
}
else if (choose==2)
{
cout<<endl<<"中序遍历:"<<endl;
cout<<"选择递归(0)非递归(1)"<<endl;
int ch;
cin>>ch;
if (ch==0)
ouldr1(head);
else
ouldr2();
}
else if (choose==3)
{
cout<<endl<<"后序遍历:"<<endl;
cout<<"选择递归(0)非递归(0)"<<endl;
int ch;
cin>>ch;
if (ch==0)
oulrd1(head);
else
oulrd2();
}
else if (choose==4)
{
cout<<endl<<"层序遍历:"<<endl;
floor();
}
}
int make1(int l,int r)
{
int noww=now;
T[noww].data=preord[now];
if (l==r)
{
T[noww].lson=T[noww].rson=-1;
return noww;
}
int mid;
for (int i=l;i<=r;i++)
if (midord[i]==preord[now])
{
mid=i;
break;
}
if (mid!=l)
{
now++;
T[noww].lson=make1(l,mid-1);
T[T[noww].lson].father=noww;
}
else
{
T[noww].lson=-1;
}
if (mid!=r)
{
now++;
T[noww].rson=make1(mid+1,r);
T[T[noww].rson].father=noww;
}
else
{
T[noww].rson=-1;
}
return noww;
}
void make2()
{
int sta
[3];
int l=1,r=n;
int noww=1;
int stn=1;
int mid;
sta[1][0]=0;sta[1][1]=1;sta[1][2]=n;
while (stn>0)
{
int fa=sta[stn][0];
l=sta[stn][1],r=sta[stn][2];
T[noww].data=preord[noww];
T[noww].father=fa;
if (fa!=0)
{
if (T[fa].lson!=0)
T[fa].rson=noww;
else
T[fa].lson=noww;
}
stn--;
int a,b,c;
for (int i=l;i<=r;i++)
if (midord[i]==preord[noww])
{
mid=i;
break;
}
if (mid!=l)
{
stn++;
a=noww;
b=l;
c=mid-1;
}
else
{
T[noww].lson=-1;
}
if (mid!=r)
{
if (mid==l) stn++;
sta[stn][0]=noww;
sta[stn][1]=mid+1;
sta[stn][2]=r;
if (mid!=l) stn++;
}
else
{
T[noww].rson=-1;
}
if (mid!=l)
{
sta[stn][0]=a;
sta[stn][1]=b;
sta[stn][2]=c;
}
noww++;
}
return;
}
void build()
{
int l=1,r=n;
now=1;
cout<<"选择建树方式:1、递归 2、非递归"<<endl;
int choose;
cin>>choose;
if (choose==1)
{
int head=make1(l,r);
}
else
make2();
return;
}
void init(int n,int ord[])
{
for (int i=1;i<=n;i++) cin>>ord[i];
return;
}
void start()
{
cout<<"请输入树的节点的个数:";
cin>>n;
T=new Tree
;
for (int i=1;i<=n;i++)
{
T[i].data=T[i].father=T[i].lson=T[i].rson=0;
}
cout<<"请输入树的前序遍历:";
preord=new int
;
init(n,preord);
cout<<"请输入树的中序遍历:";
midord=new int
;
init(n,midord);
return;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息