一、概述
给出一棵二叉树的中序和后序遍历,求其层序遍历。
408时DS部分很喜欢出的题,现在要用代码实现。
原理很简单。
首先用一个函数重建二叉树,然后层序遍历即可。
第一次做还是有几个小坑的。
二、分析
首先是重建二叉树。代码如下:
Node* create(int inhead, int inend, int posthead, int postend)
{
if (posthead>postend)//递归出口
return NULL;
Node* root = new Node;//新建根节点
root->data = postorder[postend];//根节点数据域赋值
//printf("%d",root->data);
int i = inhead;
for (i = inhead; i <= inend; i++)
if (inorder[i] == root->data)
break;//找到根节点在中序的位置
int leftNumber = i - inhead;
//root->lchild=create(inhead,i-1,posthead,i-1);//根节点左右子树
//在后序遍历中,找到左子树的元素时,不能用[posthead,i-1],要用[posthead,posthead+leftNumber-1]
root->lchild = create(inhead, i - 1, posthead, posthead + leftNumber - 1);
//root->rchild=create(i+1,inend,i,postend-1);
//右子树也一样,总结起来就是除了中序序列,找子树元素时要用左子树个数来定位
root->rchild = create(i + 1, inend, posthead + leftNumber, postend - 1);
//千万不要忘了return
return root;
}
二叉树是由递归定义的,因此重建二叉树要使用递归函数。
函数的返回值是节点指针,这是一定要注意的。如果没有返回值,那么根节点指针就是0x00,这是易犯的错误。
四个参数分别是目前要重建的二叉(子)树的中序遍历节点下标,后序遍历节点下标。
首先判断递归出口,以除中序以外的序列的左下标大于右下标为出口。
其次申请内存,建新节点,用new关键字,为节点赋值。
再然后根据后序遍历的下标定位根节点在中序遍历的下标。
最后递归调用函数。
一定要注意函数参数。
然后是层序遍历。如下:
void levelorder(Node* root)
{
queue<Node*> q;
q.push(root);
while (!q.empty())
{
Node* newnode = q.front();
q.pop();
N--;
printf("%d", newnode->data);
if (N > 0)
printf(" ");
if (newnode->lchild != NULL)
q.push(newnode->lchild);
if (newnode->rchild != NULL)
q.push(newnode->rchild);
}
}
是由BFS改进而来的,比BFS简单些。使用队列实现。注意队列的元素是节点指针而不是节点。
三、总结
二叉树的遍历、重建也是很重要的知识点,要熟练掌握。
PS:代码如下:
#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
struct Node
{
int data;
Node* lchild;
Node* rchild;
};
int inorder[30] = { 0 };//中序序列
int postorder[30] = { 0 };//后序序列
int N;
Node* create(int inhead, int inend, int posthead, int postend)
{
if (posthead>postend)//递归出口
return NULL;
Node* root = new Node;//新建根节点
root->data = postorder[postend];//根节点数据域赋值
//printf("%d",root->data);
int i = inhead;
for (i = inhead; i <= inend; i++)
if (inorder[i] == root->data)
break;//找到根节点在中序的位置
int leftNumber = i - inhead;
//root->lchild=create(inhead,i-1,posthead,i-1);//根节点左右子树
//在后序遍历中,找到左子树的元素时,不能用[posthead,i-1],要用[posthead,posthead+leftNumber-1]
root->lchild = create(inhead, i - 1, posthead, posthead + leftNumber - 1);
//root->rchild=create(i+1,inend,i,postend-1);
//右子树也一样,总结起来就是除了中序序列,找子树元素时要用左子树个数来定位
root->rchild = create(i + 1, inend, posthead + leftNumber, postend - 1);
//千万不要忘了return
return root;
}
void levelorder(Node* root)
{
queue<Node*> q;
q.push(root);
while (!q.empty())
{
Node* newnode = q.front();
q.pop();
N--;
printf("%d", newnode->data);
if (N > 0)
printf(" ");
if (newnode->lchild != NULL)
q.push(newnode->lchild);
if (newnode->rchild != NULL)
q.push(newnode->rchild);
}
}
int main()
{
scanf("%d", &N);
int i;
for (i = 0; i<N; i++)
scanf("%d", &postorder[i]);
for (i = 0; i<N; i++)
scanf("%d", &inorder[i]);
Node* root = create(0, N - 1, 0, N - 1);
levelorder(root);
}