PAT—1020 Tree Traversals (25 分) 重建、遍历二叉树

博客主要介绍了如何根据后序和中序序列重建二叉树,并详细解析了二叉树的先序、中序、后序遍历及层次遍历的递归和非递归算法,还指出了在实现过程中的常见错误点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题目大意

输入给出了一棵二叉树的后序和中序序列,请输出层次遍历序列。

二叉树的遍历

  • 先序遍历
  • 中序遍历
  • 后序遍历
  • 层次遍历

先中后指的是对根节点的访问,无论是先中后哪种遍历,左子树都优于右子树。

先序遍历

  • 递归算法
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:若是那种要求求出某一结点的所有祖先结点,可以先后序访问到这个结点,然后堆栈中存放的既是该结点的祖先结点。

层次遍历

借助队列实现

基本思路:

  1. 将根结点 root 加入队列q
  2. 取出队首结点,访问
  3. 如果该结点有左孩子,将左孩子入队列
  4. 如果该结点有右孩子,将左孩子入队列
  5. 返回步骤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:因为先序或者后序遍历序列或者层次可以提供根结点,然后根据中序序列可以分出该结点的左右子树。

  1. 设先序序列的区间为:[preL,preR]
  2. 设中序序列的区间为:[inL,inR]
  3. 在中序序列中找到preL对应的结点的位置,设下标为k
  4. 找到左子树的结点个数为 numLeft=k-inL;
  • 得到左子树的先序序列区间为[preL+1,preL+numLeft],左子树的中序序列区间为[inL,k-1];
  • 右子树的先序序列区间为[pre+numLeft+1,preR],右子树的中序序列区间为[k+1,inR]
  1. 递归,直到先序序列的长度等于零
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值