数据结构-二叉树遍历,根据任意2个遍历序列还原二叉树

该代码实现了根据二叉树的前序、中序、后序遍历结果还原二叉树的Java方法。由于先序和后序遍历无法精确判断子树位置,故在缺少中序遍历时,结果可能不唯一,尤其是子树为空的情况。文章提供了详细的代码实现和解释。
摘要由CSDN通过智能技术生成
public class Tree {

	public static void main(String[] args) {
		int[] pre = {1, 2, 4, 7, 3, 5, 6, 8};
		int[] mid = {4, 7, 2, 1, 5, 3, 8, 6};
		int[] post = {7, 4, 2, 5, 8, 6, 3, 1};

		TreeNode treeNode1 = preAndIn(pre, mid);
		System.out.println(treeNode1);

		TreeNode treeNode2 = inAndPost(mid, post);
		System.out.println(treeNode2);

		TreeNode treeNode3 = preAndPost(pre, post);
		System.out.println(treeNode3);

		showPre(treeNode1);
		System.out.println("\r");
		showIn(treeNode1);
		System.out.println("\r");
		showPost(treeNode1);
		System.out.println("\r");
	}

	/**
	* 前序遍历二叉树
	* @param node
	* @return void
	* @date 2023/5/16 16:43
	* @author: hwm
	*/
	public static void showPre(TreeNode node) {
		if (node == null) {
			return;
		}
		System.out.print(node.getData());
		showPre(node.left);
		showPre(node.right);
	}

	/**
	* 中序遍历二叉树
	* @param node
	* @return void
	* @date 2023/5/16 16:43
	* @author: hwm
	*/
	public static void showIn(TreeNode node) {
		if (node == null) {
			return;
		}
		showIn(node.left);
		System.out.print(node.getData());
		showIn(node.right);
	}

	/**
	* 后序遍历二叉树
	* @param node
	* @return void
	* @date 2023/5/16 16:43
	* @author: hwm
	*/
	public static void showPost(TreeNode node) {
		if (node == null) {
			return;
		}
		showPost(node.left);
		showPost(node.right);
		System.out.print(node.getData());
	}

	/**
	* 根据二叉树的前序和中序遍历结果还原二叉树
	* @param pre
	* @param mid
	* @return test.Tree.TreeNode
	* @date 2023/5/16 16:37
	* @author: hwm
	*/
	public static TreeNode preAndIn(int[] pre, int[] mid) {
		if (pre.length == 0) {
			return null;
		}
		// 先序第一位为当前子树的根
		TreeNode node = new TreeNode(pre[0]);
		if (pre.length == 1){
			return node;
		}
		int rootIndex = -1;
		// 查找根在中序中的位置,用于区分左子树和右子树
		for (int i = 0; i < mid.length; i++) {
			if (node.getData() == mid[i]) {
				rootIndex = i;
				break;
			}
		}
		if (rootIndex == -1) {
			// 异常情况直接退出
			System.out.println("无法判定子树,自动退出");
			System.out.println("pre:" + pre);
			System.out.println("mid:" + mid);
			return node;
		}
		// 先序第一位是根所以跳过,通过中序列中根的位置能确定左子树的元素长度,用来截取先序中左子树,Arrays.copyOfRange的第三个参数是闭区间(不包括)所以要加1,截取的元素是左子树的先序列
		// 中序列中根的左侧就是左子树,所以从0-rootIndex就是左子树的中序列结果
		node.left = preAndIn(Arrays.copyOfRange(pre,1,rootIndex + 1), Arrays.copyOfRange(mid, 0, rootIndex));
		// 右子树的先序列就是rootIndex+1(+1是因为rootIndex位的元素是属于左子树的) -pre.length的结果,右子树的中序列类似
		node.right = preAndIn(Arrays.copyOfRange(pre,rootIndex + 1, pre.length), Arrays.copyOfRange(mid, rootIndex + 1, mid.length));
		return node;
	}

	/**
	* 根据二叉树的中序和后序遍历结果还原二叉树
	* @param mid
	* @param post
	* @return test.Tree.TreeNode
	* @date 2023/5/16 17:01
	* @author: hwm
	*/
	public static TreeNode inAndPost(int[] mid, int[] post) {
		if (post.length == 0){
			return null;
		}
		TreeNode node = new TreeNode(post[post.length - 1]);
		if (post.length == 1){
			return node;
		}
		int rootIndex = -1;
		for (int i = 0; i < mid.length; i++) {
			if (node.getData() == mid[i]) {
				rootIndex = i;
				break;
			}
		}
		if (rootIndex == -1) {
			// 异常情况直接退出
			System.out.println("无法判定子树,自动退出");
			System.out.println("mid:" + mid);
			System.out.println("post:" + post);
			return node;
		}
		node.left = inAndPost(Arrays.copyOfRange(mid, 0, rootIndex), Arrays.copyOfRange(post, 0, rootIndex));
		node.right = inAndPost(Arrays.copyOfRange(mid, rootIndex + 1, mid.length), Arrays.copyOfRange(post, rootIndex, post.length - 1));
		return node;
	}

	/**
	 * 根据二叉树的先序和后序遍历结果还原二叉树,非精确,由于缺少中序遍历,可能出现左右子树位置错误的情况(目前测试发现只发生在左或右子树为空的情况)
	 * @param pre
	 * @param post
	 * @return test.Tree.TreeNode
	 * @date 2023/5/16 17:01
	 * @author: hwm
	 */
	public static TreeNode preAndPost(int[] pre, int[] post) {
		if (pre.length == 0){
			return null;
		}
		TreeNode node = new TreeNode(pre[0]);
		if (pre.length == 1){
			return node;
		}
		int leftIndex = -1;
		for (int i = 0; i < post.length; i++) {
			if (pre[1] == post[i]) {
				leftIndex = i;
				break;
			}
		}
		if (leftIndex == -1) {
			// 异常情况直接退出
			System.out.println("无法判定子树,自动退出");
			System.out.println("pre:" + pre);
			System.out.println("post:" + post);
			return node;
		}
		// 先序和后序无法确定子树的根的位置,但是能通过先确定左子树,再圈定右子树,由遍历结果可以判定,先序第二位是左子树的根。
		// 通过左子树的根 找到左子树根ai后序列中的位置,通过在后序列中的位置长度,圈定先序中左子树的范围,剩下的就是右子树,依此类推
		node.left = preAndPost(Arrays.copyOfRange(pre, 1, leftIndex + 2), Arrays.copyOfRange(post, 0, leftIndex + 1));
		node.right = preAndPost(Arrays.copyOfRange(pre, leftIndex + 2, pre.length), Arrays.copyOfRange(post, leftIndex + 1, post.length - 1));
		return node;
	}

	@Data
	static class TreeNode {
		private int data;
		private TreeNode left;
		private TreeNode right;

		public TreeNode(int data) {
			this.data = data;
		}
	}
}

根据先序和后序还原二叉树,结果不精确。左子树或右子树为空的情况下,默认都会归为左子树
因为后序遍历是左右根,在左子树或右子树为空的情况下不能确定是左子树还是右子树,这里统一归为左子树
所以根据先序和后序还原二叉树只是二叉树的一种可能,并不能精确还原
参考文章:https://blog.csdn.net/baidu_39479284/article/details/120862098

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值