洛谷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);
	}
}

### 二叉树遍历的Python实现 #### 定义二叉树节点类 为了方便操作,定义一个简单的二叉树节点类 `TreeNode`: ```python class TreeNode: def __init__(self, value=0, left=None, right=None): self.value = value self.left = left self.right = right ``` #### 迭代法实现遍历 迭代法通过栈来模拟递归过程。每次访问根节点后将其压入栈中,并优处理左子树。 ```python def preorder_traversal_iterative(root): if not root: return [] stack, result = [root], [] while stack: node = stack.pop() result.append(node.value) # 注意这里的顺:因为栈是后进出, # 所以要将右孩子压入栈,再把左孩子压进去 if node.right: stack.append(node.right) if node.left: stack.append(node.left) return result ``` 此方法适用于不想使用额外空间保存递归调用的情况[^1]。 #### 递归法实现遍历 递归方式更加直观易懂,直接按照“根->左->右”的顺依次访问各个结点即可。 ```python def preorder_traversal_recursive(root, result=[]): if root is None: return result.append(root.value) # 访问根节点 preorder_traversal_recursive(root.left, result) # 遍历左子树 preorder_traversal_recursive(root.right, result) # 遍历右子树 return result ``` 这种方法利用了函数调用栈自动管理待处理节点的信息,在大多数情况下都足够高效[^2]。 #### 动态演示版本 对于更生动的理解,还可以创建图形化界面展示遍历时各节点的变化情况。这通常涉及到GUI库的应用,比如Tkinter等工具包可以帮助构建这样的应用[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值