简介:
二叉树的应用十分广泛。根据二叉树的前序序列和中序序列,可以构造出二叉树。构造方法可以采用递归和非递归。二叉树的遍历通常有四种方法,分别是前序遍历,中序遍历,后序遍历,层序遍历。其中,前序,中序,后序又有递归和非递归两种写法。求最近公共祖先的方法同样有很多。这里选择了一种时间、空间复杂度较低的方法。
本文主要分为以下几个部分:
-
递归与非递归建树
-
不同方式的遍历
-
寻找最近公共父节点
正文:
-
建树
-
递归
-
每次搜到中序序列中当前节点的位置,以此位置为界,将中序序列中的区间一分为二,然后分别传给左、右子树进行递归。
-
非递归
栈中存储当前节点的子树区间(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[N];
- 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[n].data<<" ";
- if (T[n].lson!=-1) oudlr1(T[n].lson);
- if (T[n].rson!=-1) oudlr1(T[n].rson);
- return;
- }
- void oudlr2()
- {
- int sta[N];
- 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[n].lson!=-1) ouldr1(T[n].lson);
- cout<<T[n].data<<" ";
- if (T[n].rson!=-1) ouldr1(T[n].rson);
- return;
- }
- void ouldr2()
- {
- int boo[N];
- int sta[N];
- 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[n].lson!=-1) oulrd1(T[n].lson);
- if (T[n].rson!=-1) oulrd1(T[n].rson);
- cout<<T[n].data<<" ";
- return;
- }
- void oulrd2()
- {
- int sta[N];
- int sta1[N];
- 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[N];
- 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[N][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[N];
- for (int i=1;i<=n;i++)
- {
- T[i].data=T[i].father=T[i].lson=T[i].rson=0;
- }
- cout<<"请输入树的前序遍历:";
- preord=new int[N];
- init(n,preord);
- cout<<"请输入树的中序遍历:";
- midord=new int[N];
- init(n,midord);
- return;
- }