洛谷P1030求先序排列

明明一道普及-,我却前前后后挠了快一个小时头皮。。。。
太菜了QAQ
不过最终是想出来了,经过这道题,更加理解了二叉树的结构和遍历序列,比较有意义,来分享一下。


题意非常简单,给出二叉树的中序遍历和后序遍历,求这颗二叉树的先序遍历。

一开始拿到这个题有点不知所措,不知如何遍历,别说是先序遍历了,就是找出每个节点的位置,也是毫无头绪 (虽然找出了位置就可以搞出先序遍历)

经过一番思考发现,这个题,必须要分析二叉树节点在中序和后序遍历两种方式的分布规律。具体点说,是二叉树上某一节点位置及其子树的分布。

这里有一个思想很好的帮助了我,就是将节点的子树看成是一个整体,即一个节点的某个子树在遍历序列中必定是连续分布的。

顺着这个思路,就可以对已知数据进行分析了。


中序遍历序列

一个节点的左右子树一定连续分布在该节点的两侧(左子树在左边,右子树在右边)
用个图来表示:大概是这个样子
左右子树的根,即当前节点的左右子节点,存在于左右子树区间内的某个位置
再来一个图,图中kl和kr分别是k的左子节点和右子节点,具体是那个元素仅靠中序序列无法确定:
在这里插入图片描述

后序遍历序列

一个节点的左右子树一定连续分布在该节点的左侧,且左子树在左边,右子树在左子树与节点之间。
看图:
在这里插入图片描述
而在后序遍历中,一棵树的根节点的在整棵树中的位置是确定的,在整棵树序列的末尾
看图:
在这里插入图片描述


这样一来,不难发现两种遍历序列各自的长短处:
中序遍历:知道左右子树的分布,可根据左右边界和根节点位置计算出左右子树大小。但是不知道左右子节点的位置。
(左右边界表示以该节点为根的树在序列上的分布最左和最右位置)
后序遍历,知道左子节点的位置的位置,不知道左右子树的大小,需要左子树的大小计算出右子节点的位置上。

然后惊喜的发现,两者的长短处可以互补,进而刻画出整棵树。

大概步骤就是:

  • 从后序序列拿出一个节点
  • 找到中序序列中的对应位置
  • 根据左右边界计算出左右子树的大小
  • 在后序序列中确定左右子节点
  • 递归这个过程。

完成以上想法,还需要一个映射:节点到中序遍历下标的映射,便于从后序序列中得到节点,确定到中序序列上。


最后,就是递归的顺序和问题处理的边界:
从根节点开始的递归,采用先序遍历方法,边遍历边打印出结果。
后序序列去最后一个元素开始。(根节点位于整棵树的右侧)
中序序列的初始边界为首元素和尾元素。(整棵树都是以根节点为根的)

注:注意判断左右子树不存在的情况!!!


代码:

import java.util.Scanner;

public class Main {
	static Scanner scan = new Scanner(System.in);
	static char[] mid = scan.next().toCharArray();
	static char[] back = scan.next().toCharArray();
	static int[] pos = new int[100];
	
	//以后序序列中第k为为根的子树,在中序序列中的边界
	static void dfs(int l,int r,int k)
	{
		int size = 1;
		System.out.print(back[k]);
		if(l == r)
		{
			return;
		}
		int po = pos[back[k]];//该节点在中序序列的位置
		if(po > l)//有左子树先遍历左子树
		{
			dfs(l,po - 1,k - 1 - r + po);
		}
		if(po < r)//有右子树再遍历右子树
		{
			dfs(po + 1,r,k - 1);
		}
	}
	
	public static void main(String[] args)
	{
		for(int i = 0;i < mid.length;i++)
		{
			pos[mid[i]] = i;
		}
		dfs(0,mid.length - 1,mid.length - 1);
	}
}

发布了17 篇原创文章 · 获赞 2 · 访问量 468

猜你喜欢

转载自blog.csdn.net/wayne_lee_lwc/article/details/104331308