【问题描述】
给出一个按照先序遍历得出的字符串,'#' 代表空的子节点,大写字母代表节点内容。请通过这个字符串建立二叉树,并分别采用“递归”和“非递归”的先序、中序、后序遍历的算法分别输出每一个非空节点。
【输入形式】
输入只有一行,包含一个字符串S,用来建立二叉树。保证S为合法的二叉树先序遍历字符串,节点内容只有大写字母,且S的长度不超过100。
【输出形式】
共有6行,每一行包含一串字符,表示分别按递归和非递归的先序、中序、后序遍历得出的节点内容,每个字母后输出一个空格。请注意行尾输出换行。
【样例输入】
ABC##DE#G##F###
【样例输出】
A B C D E G F
C B E G D F A
C G E F D B A
A B C D E G F
C B E G D F A
C G E F D B A
#include <iostream> #include<string.h> #include<stdio.h> #include<algorithm> #define MAX 100 using namespace std; typedef struct tree { char ch; struct tree *Lchild; struct tree *Rchild; }Nodetree,*Betree; typedef struct stack1 { Betree a[MAX]; int top; }Stack1; typedef struct stack2//后序非递归遍历 { Betree a; bool t; }Stack2; void push(Stack1 &s,Betree b) { s.a[++s.top]=b; } Betree pop(Stack1 &s) { s.top--; return s.a[s.top+1]; } void CreateTree(Betree *r)//创建链表 { char ch; ch=getchar(); if(ch=='#') *r=NULL; else { (*r)=new Nodetree; (*r)->ch=ch; CreateTree(&((*r)->Lchild)); CreateTree(&((*r)->Rchild)); } } void Nopre(Betree r)//非递归先序遍历 { Stack1 s1; s1.top=-1; while(r!=NULL) { cout<<r->ch<<" "; push(s1,r);//进栈 if(r->Lchild!=NULL) { r=r->Lchild; } else if(s1.top!=-1) { while(s1.top!=-1) { r=pop(s1);//出栈 r=r->Rchild; if(r!=NULL)break;//如果当前结点不是叶子结点,就退出,对当前结点的右结点进行循环。 } } else r=NULL; } } void NoIn(Betree r)//非递归中序遍历 { Stack1 s1; s1.top=-1; while(r!=NULL) { push(s1,r);//进栈 if(r->Lchild!=NULL) { r=r->Lchild; } else if(s1.top!=-1) { while(s1.top!=-1) { r=pop(s1);//出栈 cout<<r->ch<<" "; r=r->Rchild; if(r!=NULL)break;//如果当前结点不是叶子结点,就退出,对当前结点的右结点进行循环。 } } else r=NULL; } } void NoLast(Betree r)//非递归后序遍历 { Stack2 s2[100]; int top=-1; do { while(r!=NULL)//有左子结点就一直往左 { s2[++top].a=r; r=r->Lchild; s2[top].t=false;//每个都赋false说明每个都往左 } while(top!=-1&&s2[top].t==true)//如果左右都判断完了,说明那个节点两边都是true,这条语句就要往上(跟结点方向)循环多次 { r=s2[top--].a;//出栈 cout<<r->ch<<" "; } if(top!=-1) { s2[top].t=true; r=s2[top].a->Rchild;//左边完,换右边 } }while(top!=-1); } void pre(Betree a) { if(a==NULL) return; else { cout<<a->ch<<" "; pre(a->Lchild); pre(a->Rchild); } } void in(Betree a) { if(a==NULL) return; else { in(a->Lchild); cout<<a->ch<<" "; in(a->Rchild); } } void last(Betree a) { if(a==NULL) return; else { last(a->Lchild); last(a->Rchild); cout<<a->ch<<" "; } } int main() { Betree r=NULL; r=new Nodetree; CreateTree(&r); pre(r); cout<<endl; in(r); cout<<endl; last(r); cout<<endl; Nopre(r); cout<<endl; NoIn(r); cout<<endl; NoLast(r); } [点击并拖拽以移动]
注释:此题包含了三种递归遍历二叉树和三种非递归遍历二叉树的方法
【问题描述】假设二叉树采用二叉链表方式存储,root指向根结点,p所指结点和q所指结点为二叉树中的两个不同结点,且互不成为根到该结点的路径上的点,编程求解距离它们最近的共同祖先。
【输入形式】二叉树的前序和中序遍历序列,用以创建该二叉树的链式存储结构;以及二叉树的两个结点数据 x 和 y
【输出形式】结点数据值为 x 和结点数据值为 y 的最近的共同祖先,若没有共同祖先则输出NULL,请注意一个结点本身不能成为另一个结点的共同祖先。
【样例输入】
GABDCEF
BDAEFCG
DF
【样例输出】
A
#include <iostream> #include<string.h> #include<stdio.h> #include<algorithm> #define MAX 100 using namespace std; typedef struct tree { char ch; struct tree *Lchild; struct tree *Rchild; }Nodetree,*Betree; Betree ans; bool flag=false; void CreateTree(Betree *a,char pre[],char in[],int preL,int preR,int inL,int inR)//先序数组+中序数组创建链表 { if(inL>inR) a=NULL; else { *a=new Nodetree; (*a)->ch=pre[preL];//注意“*a”打括号!! int mid=inL; while(in[mid]!=pre[preL]) { mid++; } CreateTree(&((*a)->Lchild),pre,in,preL+1,preL+mid-inL,inL,mid-1); CreateTree(&((*a)->Rchild),pre,in,preL+mid-inL+1,preR,mid+1,inR); } } bool search(Betree a,char x,char y)//后序递归遍历找最近母结点 { if(a==NULL) return false; else { bool Lh=search(a->Lchild,x,y); bool Rh=search(a->Rchild,x,y); if(Lh&&Rh) { ans=a; flag=true; } return Lh||Rh||(a->ch==x||a->ch==y);//只要满足一个条件就可以往上寻找共同母代 } } int main() { Betree a=NULL; a=new Nodetree; char pre[MAX]; char in[MAX]; cin>>pre; cin>>in; int preR=strlen(pre)-1; int inR=strlen(in)-1; CreateTree(&a,pre,in,0,preR,0,inR); char x,y; cin>>x>>y; search(a,x,y); if(flag) cout<<ans->ch; else cout<<"NULL"<<endl; } [点击并拖拽以移动]
问题描述】 根据一棵二叉树的中序遍历序列和后序遍历序列,求这棵树的前序遍历序列。
【输入形式】 一棵树的中序遍历序列和该树后序遍历序列。输入序列中仅含有小写字母,且没有重复的字母
【输出形式】 一棵树的前序遍历序列
【样例输入】
dbeafcgdebfgca
【样例输出】
abdecfg
#include <iostream> #include<string.h> #include<stdio.h> #include<algorithm> #define MAX 10000 using namespace std; typedef struct tree { char ch; struct tree *Lchild; struct tree *Rchild; }Nodetree,*Betree; void CreateTree(Betree *r,char Last[],char In[],int LastL,int LastR,int il,int ir)//中序数组+后序数组递归创建二叉链表 { if(il>ir) *r=NULL; else { *r=new Nodetree; (*r)->ch=Last[LastR]; int mid=il; while(In[mid]!=Last[LastR]) { mid++; } CreateTree(&((*r)->Lchild),Last,In,LastL,LastL+mid-il-1,il,mid-1); CreateTree(&((*r)->Rchild),Last,In,LastL+mid-il,LastR-1,mid+1,ir); } } void print(Betree r) { if(r==NULL) return; else { cout<<r->ch; print(r->Lchild); print(r->Rchild); } } int main() { char Last[MAX],In[MAX]; cin>>In; cin>>Last; int LastR=strlen(Last)-1; int ir=strlen(In)-1; Betree r=NULL; r=new Nodetree; CreateTree(&r,Last,In,0,LastR,0,ir); print(r); } [点击并拖拽以移动]
注释:这两题放在一起,因为中序+后序和前序+中序建立二叉链表的方式很相似,可以用来比较。注意,前序和后序是不能确定一个唯一的二叉树的
【问题描述】课后作业习题25:n个结点的完全二叉树顺序存储在一维数组a中,设计一个算法,实现对此二叉树的先序遍历。
【输入形式】一维数组a,以#结束输入,请接收后存储在一维数组a中
【输出形式】先序遍历序列
【样例输入】ABCDEF#
【样例输出】ABDECF
#include <iostream> #include<string.h> #include<stdio.h> #include<algorithm> #include<cmath> #define MAX 100 using namespace std; typedef struct tree { char ch; struct tree *Lchild; struct tree *Rchild; }Nodetree,*Betree; void CreateTree(Betree *a,char ch[])//创建二叉链表 { int len=strlen(ch)-1; int h=log(len)/log(2)+1;//完全二叉树的深度 // cout<<h<<endl; int x=-1;//一维数组的下表 int y=0;//pre指针数组的下标 int z=0;//pre指针数组中当前用的结点的下标 Betree pre[MAX]; pre[0]=*a; for(int i=1;i<=h-2;i++) { for(int j=1;j<=pow(2.0,i-1);j++) { pre[z]->ch=ch[++x]; Betree c=NULL,d=NULL; c=new Nodetree; d=new Nodetree; // c->ch=ch[++x]; // d->ch=ch[++x]; pre[z]->Lchild=c; pre[z]->Rchild=d; pre[++y]=c; pre[++y]=d; z++; } } int g;//记录倒数第二层的第一个结点在pre中的位置 bool flag=true; while(z<=y)//把倒数第二层的结点赋值并链接结点; { if(flag) { g=z; flag=false; } pre[z]->ch=ch[++x]; Betree c=NULL,d=NULL; c=new Nodetree; d=new Nodetree; // c->ch=ch[++x]; //d->ch=ch[++x]; pre[z]->Lchild=c; pre[z]->Rchild=d; d->Lchild=NULL; d->Rchild=NULL; c->Lchild=NULL; c->Rchild=NULL; z++; } while(ch[x]!='#')//对最后一层的结点进行赋值 { x++; if(ch[x]=='#') { pre[g]->Lchild=NULL; break; } else pre[g]->Lchild->ch=ch[x]; x++; if(ch[x]=='#') { pre[g]->Rchild=NULL; break; } else pre[g]->Rchild->ch=ch[x]; g++; } } void print(Betree a) { if(a==NULL) return; else { cout<<a->ch; print(a->Lchild); print(a->Rchild); } } int main() { char ch[MAX]; cin>>ch; Betree a=NULL; a=new Nodetree; CreateTree(&a,ch); //cout<<endl; print(a); }
注释:本题关键要把一个顺序储存的一维数组二叉树转化成二叉链表储存形式,然后先序输出即可
【问题描述】 考研真题:给定一颗二叉树,要求从下至上按层遍历二叉树,每层的访问顺序是从左到右,每一层单独输出一行。
【输入形式】 广义表表示的二叉树,结点元素类型为整型,且都大于0,例如:1( 2( 3 ( 4, 5 ) ), 6( 7, 8( 9, 10 ) ) )
【输出形式】 从下至上,打印每一层的结点元素值,元素间以空格隔开。每层的访问顺序是从左到右,每一层单独输出一行。
【样例输入】 1(2(3(4,5)),6(7,8(9,10))),字符串内没有空格
【样例输出】
4 5 9 10
3 7 8
2 6
1
#include <iostream> #include<string.h> #include<stdio.h> #include<algorithm> #include<cmath> #define MAX 100 using namespace std; typedef struct tree { int ch; struct tree *Lchild; struct tree *Rchild; }Nodetree,*Betree; typedef struct queue { Betree num[MAX]; int l; int r; }Queue; typedef struct order { int arr[MAX]; int count1; }Order;//用于统计二叉树每层的元素以及每层的个数 Betree pop(Queue &a) { if(a.r==a.l) exit(0); else { a.l++; return a.num[a.l-1]; } } void push(Queue &a,Betree b) { if(a.r==MAX) exit(0); else { a.num[a.r]=b; a.r++; } } void aa(Betree a) { if(a==NULL) return; else { cout<<a->ch; aa(a->Lchild); aa(a->Rchild); } } Betree Createtree(Betree a,char ch[]) { int arr[MAX]; int num=0;//字符串转化为整形数组后的数组长度 int k=0;//判断给左节点赋值还是右结点 Betree p[MAX]; int top=-1; Betree s=NULL; for(int i=0;ch[i]!='\0';i++,num++) { switch(ch[i]) { case '(':arr[num]=-1;break; case ')':arr[num]=-2;break; case ',':arr[num]=-3;break; default: int temp=0; int j; for(j=i;ch[j]>='0'&&ch[j]<='9';j++) temp=temp*10+ch[j]-'0'; arr[num]=temp; i=j-1; break; } } // for(int i=0;i<num;i++) // cout<<arr[i]; //cout<<1<<endl; for(int i=0;i<num;i++) { switch(arr[i]) { case -1: p[++top]=a; k=1;//左子树赋值 break; case -2: top--;//退回结点 k=2;//右子树赋值 break; case -3: k=2; break; default: a=new Nodetree; a->ch=arr[i]; a->Lchild=NULL; a->Rchild=NULL; if(k==1) p[top]->Lchild=a; else if(k==2) p[top]->Rchild=a; break; } } return p[0]; } void LayerOrder(Betree a) { Order o[MAX]; int i=1;//o[i]代表二叉树第i层 int ik=1;//本层元素个数 int j=0;//每个o[]的中数组的长度 int y=0;//代表出列一个结点的次数,当y++直至等于ik是,本层遍历完毕 Queue c; c.l=0; c.r=0; push(c,a);//二叉树第一个节点入队 // cout<<c.num[c.l]->ch<<endl; while(c.l!=c.r) { Betree x=pop(c); o[i].arr[y]=x->ch; // cout<<o[i].arr[y]; y++; if(x->Lchild) { push(c,x->Lchild); j++; } if(x->Rchild) { push(c,x->Rchild); j++; } if(y==ik) { o[i].count1=ik;//每层长度; i++;//层数+1; ik=j;//下一层的元素个数 j=0; y=0; // cout<<c.l<<" "<<c.r<<endl; } } //cout<<1<<endl; for(int k=i-1;k>=1;k--) { for(int z=0;z<o[k].count1;z++) { cout<<o[k].arr[z]<<" "; } cout<<endl; } } int main() { Betree a=NULL; a=new Nodetree; char ch[MAX]; cin>>ch; a=Createtree(a,ch); // aa(a); //cout<<1<<endl; LayerOrder(a); }
注释:两个关键:
1.根据广义表创建二叉链表(1.将字符串转换为整形数组2.根据整形数组,遇到左括号就在betree指针数组中存入当前指针,并判定下一个如果是数值就将betree数组最后一个指针(top)的左子树指向新建的指针,如果遇到右括号就top--,使p[top]的右指针指向新建的指针,如果遇到逗号则p【top】的右指针直接指向当前指针)
2.层次遍历