题目描述
本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的先序遍历结果。
输入格式
第一行给出正整数N (≤30),是树中结点的个数。随后两行,每行给出N 个整数,分别对应后序遍历和中序遍历结果,数字间以空格分隔。题目保证输入正确对应一棵二叉树。
输出格式
在一行中输出Preorder: 以及该树的先序遍历结果。
输入样例
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出样例
Preorder: 4 1 3 2 6 5 7
题目不过多复述,看了其他博客,感觉讲的都不清楚,公式推导怎么来的根本没有说清楚,本博客重点讲一下推导过程!
#include<iostream>
#include<vector>
using namespace std;
struct node
{
int data;
node* left = NULL, * right = NULL;
};
typedef node* tree;
int num;
vector<int>post, in;
// ax-ay 是遍历后序表的范围 bx-by是中序表的范围
void create_tree(tree &t,int ax, int ay, int bx, int by)
{
if (ax > ay)
return;
t = new node;
int root = post[ay],index ;
t->data = root;
for (int i = bx; i <= by; i++)
{
if (in[i] == root)
{
index = i;
break;
}
}
//主要是这一行的推导过程尤为重要 接下来详细讲解
create_tree(t->left, ax, ax + index - bx - 1, bx, index - 1);
create_tree(t->right, ax + index - bx, ay - 1, index + 1, by);
return;
}
void preorder(tree t)
{
if (t == NULL)
return;
printf("%d ", t->data);
preorder(t->left);
preorder(t->right);
return;
}
int main()
{
cin >> num;
post.resize(num+1,0);
in.resize(num + 1, 0);
for (int i = 1; i <= num; i++)
cin >> post[i];
for (int i = 1; i <= num; i++)
cin >> in[i];
tree t;
create_tree(t,1,num,1,num);
cout << "Preorder: ";
preorder(t);
return 0;
}
直接来看公式推导:
num是数组大小,这里是7
我们知道后序遍历表的最后一个元素必定是根,我们就从这里出发。
根节点就是 root = a[ay] (后序遍历,最后一个一定是根节点)
接下来我们去中序遍历中找根节点的下标
下标 index = 4
那么在inoder表中
1-3 就是根的左子树的结点
5-7 就是根的右子树的结点
那么
左子树的结点个数就为 :index - bx
右子树的结点个数就为 :num - index
下一步我们应该做的就是返回 postorder表中,去寻找左子树在表中的范围与右子树在表中的范围。
我们接下来就进行数学推导:
左子树:
- postorder表中:
起始位置是ax = 1, 由于左子树的节点数为 index-bx 那么终点位置就为 ax + index - bx -1(自己举个例子看看,比如1-2长度为2,终点就是 1+2-1)
左子树在postorder表中的范围为 [ax,ax+index-bx-1]
- inorder表中:
起始位置就为bx,终点位置为index-1
右子树同理:
- postorder表中:
其实位置就是左子树位置的右边一个位置 即 ax+index-bx,终点位置为ay-1(ay是根节点)
右子树在postorder表中范围为 [ax+index-bx,ay-1]
- inorder表中:
从根节点的右侧一个位置,即index+1到表的末尾by!
这就是推导过程,写出来感觉清楚些,希望能够帮助大家理解!