题目大意
输入给出了一棵二叉树的后序和中序序列,请输出层次遍历序列。
二叉树的遍历
- 先序遍历
- 中序遍历
- 后序遍历
- 层次遍历
先中后指的是对根节点的访问,无论是先中后哪种遍历,左子树都优于右子树。
先序遍历
- 递归算法
void PreOrder(node* root)
{
if(root==null){
return;
}
else{
visit(root);
PreOrder(root->lchild);
PreOrder(root->lchild);
}
}
- 非递归算法
while(栈不空||p!=NULL)
{
while(P!=NULL){
访问;
入栈;
往左;
}
if(栈不空){
出栈;
往右;
}
}
void PreOrder(node* root)
{
node* stack[N],p;
int top=-1;
if(root==null){
return;
}
p=root;
while(p!=null||top!=-1){
while(p!=null){
visit(p);
stack[++top]=p;
p=p->lchild;
}
if(top!=-1){
p=stack[top--];
p=p->rchild;
}
else return;
}
}
中序遍历
- 递归算法
void INOrder(node* root)
{
if(root==null){
return;
}
else{
PreOrder(root->lchild);
visit(root);
PreOrder(root->lchild);
}
}
- 非递归算法
while(栈不空||p!=NULL)
{
while(P!=NULL){
入栈;
往左;
}
if(栈不空){
访问;
出栈;
往右;
}
}
后序遍历
- 递归算法
void PostOrder(node* root)
{
if(root==null){
return;
}
else{
PreOrder(root->lchild);
PreOrder(root->lchild);
visit(root);
}
}
- 非递归算法
while(栈不空||p!=NULL)
{
while(P!=NULL){
入栈;
往左;
}
if(栈不空){
if(第一次在栈中){
出栈;
往右;
入栈;
}
else if(第二次在栈中){
出栈;
访问;
}
}
}
区别第一次还是第二次在栈中,可以用结点地址,和结点地址取反加以区别,即 if(stack[top]>0) 表示第一次在栈中。
Ps:若是那种要求求出某一结点的所有祖先结点,可以先后序访问到这个结点,然后堆栈中存放的既是该结点的祖先结点。
层次遍历
借助队列实现
基本思路:
- 将根结点 root 加入队列q
- 取出队首结点,访问
- 如果该结点有左孩子,将左孩子入队列
- 如果该结点有右孩子,将左孩子入队列
- 返回步骤2,直到队列为空
代码
void LayerOrder(node* root)
{
queue<node*> q;//用来存放结点
q.push(root);
while(!q.empty())
{
node* p=q.front();
visit(p);
if(p->lchild!=NULL){
q.push(p->lchild);
}
if(p->rchild!=NULL){
q.push(p->rchild);
}
}
}
重建二叉树
- 根据先序遍历序列和中序遍历序列
- 根据后序遍历序列和中序遍历序列
- 根据层次遍历序列和中序遍历序列
Ps:因为先序或者后序遍历序列或者层次可以提供根结点,然后根据中序序列可以分出该结点的左右子树。
- 设先序序列的区间为:[preL,preR]
- 设中序序列的区间为:[inL,inR]
- 在中序序列中找到preL对应的结点的位置,设下标为k
- 找到左子树的结点个数为 numLeft=k-inL;
- 得到左子树的先序序列区间为[preL+1,preL+numLeft],左子树的中序序列区间为[inL,k-1];
- 右子树的先序序列区间为[pre+numLeft+1,preR],右子树的中序序列区间为[k+1,inR]
- 递归,直到先序序列的长度等于零
node* Creat(int preL,int preR,int inL,int inR)
{
if(preR<preL){
return NULL;
}
else{
node* root=new node;
root->data=Pre[preL];
for(int k=inL;k<=inR;k++){
if(In[k]==Pre[preL]){
break;
}
}
int numLeft=k-inL;
root->lchild=Creat(preL+1,preL+numLeft,inL,k-1);
root->rchild=Creat(pre+numLeft+1,preR,k+1,inR);
}
return root;
}
- 后序与中序、层次与中序做法相同,根据不同情况推出不同的下标即可。
参考代码
#include<bits/stdc++.h>
using namespace std;
#define N 30
struct node{
int data;
node* lchild;
node* rchild;
};
int Post[N],In[N],n;
node* Creat(int postL,int postR,int inL,int inR)//重建二叉树
{
int k;
if(postL>postR){
return NULL;
}
node* root=new node;
root->data=Post[postR];
for(k=inL;k<=inR;k++){
if(In[k]==Post[postR]){
break;
}
}
int numLeft=k-inL;
root->lchild=Creat(postL,postL+numLeft-1,inL,k-1);
root->rchild=Creat(postL+numLeft,postR-1,k+1,inR);
return root;
}
void LayerOrder(node* root)//层次遍历二叉树
{
int count=0;
if(root==NULL){
return;
}
queue<node*> q;
q.push(root);
while(!q.empty()){
node* temp=q.front();
q.pop();
printf("%d",temp->data);
count++;
if(count<n)printf(" ");
if(temp->lchild!=NULL){
q.push(temp->lchild);
}
if(temp->rchild!=NULL){
q.push(temp->rchild);
}
}
}
int main()
{
node* root=new node;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&Post[i]);
}
for(int i=0;i<n;i++){
scanf("%d",&In[i]);
}
root=Creat(0,n-1,0,n-1);
LayerOrder(root);
return 0;
}
出错点
- 下标,应该是 n-1,写成 n
- q.front() 仅仅是读出队首元素,没有进行出队操作,还需要一个 q.pop() ,否则就会死循环
- 递归 边界是 inL>inR ,我自己写的是 inl>=inR ,导致出错。
- 是 NULL 不是 null