原题:https://pintia.cn/problemsets/994805342720868352/problems/994805519074574336
Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, you are supposed to output the level order traversal sequence of the corresponding binary tree.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary tree. The second line gives the postorder sequence and the third line gives the inorder sequence. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print in one line the level order traversal sequence of the corresponding binary tree. All the numbers in a line must be separated by exactly one space, and there must be no extra space at the end of the line.
Sample Input:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
Sample Output:
4 1 6 3 5 7 2
题目分析:
由二叉树的后序遍历(postorder)和中序遍历(inorder)建立二叉树,并进行层次遍历。
即后序(左右根)找出根结点,中序(左根右)划分左右子树。
风格一
一步一步按照建立二叉树和层次遍历进行,建立二叉树用递归,层次遍历用队列:
/* 1020 Tree Traversals (25 分) */
#include<iostream>
#include<queue>
using namespace std;
int PostOrder[30]; // 后序
int Inorder[30]; // 中序
int Len; // 输入的树的结点数
int flag = 1; // 是否为输出的第一个
typedef struct node {
int data;
struct node* left;
struct node* right;
}BNode,*BTree;
// 解法,后序(左右根)找根,中序(左根右)进行递归
int FindElem(int* arr, int e, int len) {
// 在数组arr中找e的索引
int i;
for (i = 0; i < len && arr[i] != e; i++);
if (i == len) return -1;
else return i;
}
int FindRoot(int start, int end) {
// 从Inorder[start,...,end]中找根,返回下标
// 比较谁在PostOrder中的索引靠后
int root = Inorder[start];
int root_index = start;
int index = FindElem(PostOrder, root,Len);
for (int i = start + 1; i <= end; i++) {
int index_ = FindElem(PostOrder, Inorder[i], Len);
if (index_ > index) {
root = Inorder[i];
root_index = i;
index = index_;
}
}
return root_index;
}
void CreateTree(int start, int end, BTree& T) {
// T表示根
if (end < start || start > end) {
T = NULL; // 注意这里T是会变化的,所以需要用引用传递的方式
return;
}
int root = FindRoot(start, end);
T->left = (BNode*)malloc(sizeof(BNode));
T->right = (BNode*)malloc(sizeof(BNode));
T->data = Inorder[root];
CreateTree(start, root - 1, T->left);
CreateTree(root + 1, end, T->right);
}
void LevelTravel(BTree T) {
// 树T的层次遍历
queue<BTree> Q; // 遍历的结点队列
Q.push(T);
while (!Q.empty()) {
BTree e;
e = Q.front(); Q.pop();
if (flag == 0) {
printf(" ");
}
printf("%d", e->data);
flag = 0;
if (e->left) Q.push(e->left);
if (e->right) Q.push(e->right);
}
}
int main() {
scanf("%d", &Len);
int i;
for (i = 0; i < Len; i++) scanf("%d", &PostOrder[i]);
for (i = 0; i < Len; i++) scanf("%d", &Inorder[i]);
BTree T;
T = (BNode*)malloc(sizeof(BNode));
T->left = T->right = NULL;
CreateTree(0, Len - 1, T);
LevelTravel(T);
system("pause");
return 0;
}
风格二(简化)
同样是先根遍历建立二叉树,但是由后序遍历和中序遍历建立先序遍历的时候利用索引进行简化。
假设结点数组开始于start,结束于end。
因为后序遍历的最后一个总是树的根结点,记其在Post中索引为
r
o
o
t
root
root,所以假设在中序遍历中该结点下标为
i
i
i,则右子树共有
(
e
n
d
−
i
+
1
)
(end-i+1)
(end−i+1)个结点。所以在后序中根结点为
r
o
o
t
root
root,右子树的根节点为
r
o
o
t
−
1
root-1
root−1 ,左子树的根结点为
r
o
o
t
−
(
e
n
d
−
i
+
1
)
=
(
r
o
o
t
−
e
n
d
+
i
−
1
)
root-(end-i+1) = (root-end+i-1)
root−(end−i+1)=(root−end+i−1)。
则有
/* 1020 Tree Traversals (25 分) */
#include<iostream>
#include<queue>
using namespace std;
int Postorder[30]; // 后序
int Inorder[30]; // 中序
int Len; // 输入的树的结点数
int flag = 1; // 是否为输出的第一个
typedef struct node {
int data;
struct node* left;
struct node* right;
}BNode, *BTree;
// 后序和中序建立二叉树,即转成先序遍历
void pre(int root,int start, int end, BTree& T) {
// 注意这里的root是Post中根的索引
// 二左右子树的划分是在Inorder里,所有start和end是在中序中
// 现在Inorder中找到根结点
if (start > end) {
T = NULL;
return;
}
int i = start;
while (i < end && Inorder[i] != Postorder[root]) i++;
T = (BNode*)malloc(sizeof(BNode));
T->left = T->right = NULL;
T->data = Postorder[root];
pre(root - end + i - 1, start, i - 1, T->left); // 左子树
pre(root - 1, i + 1, end, T->right); // 右子树
}
void LevelTravel(BTree T) {
// 树T的层次遍历
queue<BTree> Q; // 遍历的结点队列
Q.push(T);
while (!Q.empty()) {
BTree e;
e = Q.front(); Q.pop();
if (flag == 0) {
printf(" ");
}
printf("%d", e->data);
flag = 0;
if (e->left) Q.push(e->left);
if (e->right) Q.push(e->right);
}
}
int main() {
scanf("%d", &Len);
int i;
for (i = 0; i < Len; i++) scanf("%d", &Postorder[i]);
for (i = 0; i < Len; i++) scanf("%d", &Inorder[i]);
BTree T;
pre(Len - 1, 0, Len - 1, T);
LevelTravel(T);
system("pause");
return 0;
}