PTA Tree Traversals Again -----知先序和中序求后序


这个题的题意暗含的信息不太好理解,开始的时候我以为构建树的过程是根据入栈和出栈的顺序构建左子树或者右子树,实际上是:
根据入栈循序得到先序遍历,根据出栈顺序得到中序遍历

思路:

我们先得到先序遍历和中序遍历的数组,在先序遍历可以知道谁是根结点,中序遍历可以知道左子树或右子树在数组中的下标范围,所以:

  1. 在先序遍历中找一个根,之后在中序遍历中找到这个根对应的左子树和右子树的索引范围
  2. 进行递归:对找到的左(右)子树的索引范围中凭借先序遍历数组找到左(右)子树的根, 返回步骤1
  3. 往后序数组中加入元素的条件:我们找到的根,他的左(右)子树只有一个元素,那就按左右顺序放到后序数组中,在把这个根也放到后序数组中

难点:

在上述中有两个难点:

  1. 在找根据中序遍历的索引范围在前序遍历中找到对应左(右)子树的根
  2. 往后序数组中放元素的条件代码化
解决:
  1. 我构建了一个Find_root函数,返回根的左子树的子根(在先序遍历中左子树的根与根相邻,而右子树的子根在先序遍历中与根相差的元素就是该根左子树所有的元素个数
  2. 我们可以得到一个左(右)子树的在中序遍历的索引范围,在这个范围中可以由1.过程找到对应的子根在中序遍历的索引 i ,
    s t a r t < i − 1 : start < i - 1: start<i1:说明左子树不只有一个元素,那就继续递归
    s t a r t = = i − 1 : start == i-1: start==i1:说明左子树只有一个元素,那就把他放到后序数组中
    s t a r t > i − 1 : start > i-1: start>i1:说明左子树为空 — 即此时是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]);
		}
	}
}

这个只是我的一个思路供大家参考,如果有更好的算法可以在下面留言哦

让我们共同进步,在算法这条道路上越走越远!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值