这个题的题意暗含的信息不太好理解,开始的时候我以为构建树的过程是根据入栈和出栈的顺序构建左子树或者右子树,实际上是:
根据入栈循序得到先序遍历,根据出栈顺序得到中序遍历
思路:
我们先得到先序遍历和中序遍历的数组,在先序遍历可以知道谁是根结点,中序遍历可以知道左子树或右子树在数组中的下标范围,所以:
- 在先序遍历中找一个根,之后在中序遍历中找到这个根对应的左子树和右子树的索引范围
- 进行递归:对找到的左(右)子树的索引范围中凭借先序遍历数组找到左(右)子树的根, 返回步骤1
- 往后序数组中加入元素的条件:我们找到的根,他的左(右)子树只有一个元素,那就按左右顺序放到后序数组中,在把这个根也放到后序数组中
难点:
在上述中有两个难点:
- 在找根据中序遍历的索引范围在前序遍历中找到对应左(右)子树的根
- 往后序数组中放元素的条件代码化
解决:
- 我构建了一个Find_root函数,返回根的左子树的子根(在先序遍历中左子树的根与根相邻,而右子树的子根在先序遍历中与根相差的元素就是该根左子树所有的元素个数)
- 我们可以得到一个左(右)子树的在中序遍历的索引范围,在这个范围中可以由1.过程找到对应的子根在中序遍历的索引 i ,
当 s t a r t < i − 1 : start < i - 1: start<i−1:说明左子树不只有一个元素,那就继续递归
当 s t a r t = = i − 1 : start == i-1: start==i−1:说明左子树只有一个元素,那就把他放到后序数组中
当 s t a r t > i − 1 : start > i-1: start>i−1:说明左子树为空 — 即此时是start == i,什么也不用做
右子树分析相同,赘述
代码:
#include <stdio.h>
#include <stdlib.h>
struct Tree {
int* First;
int N;
int* Second;
int* Third = 0;
int third;//记录此时应该放在后序的位置
}Tree;
int Find_root(int root) {//给一个根,找到他的左子根
int i;
for (i = 0;i < Tree.N;i++) {
if (Tree.First[i] == root)
break;
}
return i + 1;
}
void Second_Tree(int root, int start, int end) {//找到右树与左树
//printf("start = %d end = %d \n", start, end);
int i;
for (i = start; i <= end; i++) {
if (Tree.Second[i] == root)
break;
}//i是中序遍历中此时的根 可以凭借这个找到左树和右树 start到i-1左树; i+1到end右树
//printf("i = %d root = %d\n", i, root);
if (start < i - 1) {
Second_Tree(Tree.First[Find_root(root)], start, i - 1);//左树
}
else if (start == i - 1) {
//printf("add %d\n", Tree.Second[start]);
Tree.Third[Tree.third++] = Tree.Second[start];
}
if(i + 1 < end){
Second_Tree(Tree.First[i - start + Find_root(root)], i + 1, end);//右树
}
else if (i + 1 == end) {
//printf("add %d\n", Tree.Second[i + 1]);
Tree.Third[Tree.third++] = Tree.Second[i + 1];
}
//printf("add %d\n", Tree.Second[i]);
Tree.Third[Tree.third++] = Tree.Second[i];
}
int main() {
int N;
scanf("%d\n", &N);
//初始化
Tree.First = (int*)calloc(N, sizeof(int));//先序 例如 123456
Tree.Second = (int*)calloc(N, sizeof(int));//中序 例如 324165
Tree.Third = (int*)calloc(N, sizeof(int));//后序 例如 342651
Tree.N = N;
int first = 0, second = 0;//对与输入进行记录
char order[10];
int* stack = (int*)calloc(N, sizeof(int));
int s = 0;//建立栈的索引
for (int index = 0;index < 2 * N;index++) {
scanf("%s",order);
if (order[1] == 'u') {
scanf("%d", &Tree.First[first++]);
stack[s++] = Tree.First[first - 1];
}
else {
Tree.Second[second++] = stack[--s];
}
}//结束输入
//for (int i = 0;i < N;i++) {
// printf("%d ", Tree.Second[i]);
//}
Second_Tree(Tree.First[0],0, N-1);
for (int i = 0;i < N;i++) {
if (i != N - 1) {
printf("%d ", Tree.Third[i]);
}
else {
printf("%d", Tree.Third[i]);
}
}
}
这个只是我的一个思路供大家参考,如果有更好的算法可以在下面留言哦
让我们共同进步,在算法这条道路上越走越远!!!