根据二叉树的遍历序列重建这颗树

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动。

本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。

问题

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树

如果该二叉树的前序序列为: 1, 2, 4, 7, 3, 5, 6, 8

该二叉树的中序序列为: 4, 7, 2, 1, 5, 3, 8, 6

考察要点

二叉树的结构, 二叉树的前序遍历, 中序遍历, 后序遍历和层次遍历

二叉树前序遍历的序列中, 第一个元素就是树的根结点

二叉树后序遍历的序列中, 最后一个元素就是树的根结点

二叉树中序遍历的序列, 一个结点的左子树中的值肯定在该结点左边, 而右子树的值肯定在该结点的右边

思路

  1. 前序遍历中的第一个元素就是根结点
  2. 根据这个根结点的值, 去中序遍历中查找该值所在位置
  3. 在中序遍历中, 该值所在位置的左边就是它的左子树, 右边就是它的右子树
  4. 重复1, 2, 3步骤, 进行二叉树的递归重建

代码

二叉树的结点类

 class BinaryTreeNode {
     int value;
     BinaryTreeNode left;
     BinaryTreeNode right;
 }
复制代码

准备数据

 int[] preList = new int[]{1, 2, 4, 7, 3, 5, 6, 8};
 int[] inList = new int[]{4, 7, 2, 1, 5, 3, 8, 6};
 ​
 // public BinaryTreeNode recreateBinaryTree(int[] preList, int preStart, int preEnd, int [] inList, int inStart, int inEnd)
 // 传入前序序列, 开始结束索引, 中序序列, 开始结束索引
 c.recreateBinaryTree(preList, 0, 7, inList, 0, 7);
复制代码

代码实现

 public BinaryTreeNode recreateBinaryTree(int[] preList, int preStart, int preEnd, int [] inList, int inStart, int inEnd) {
     
     // 进行边界条件的判断
     if (preList.length == 0) return null;
     if (inList.length == 0) return null;
     if (preStart > preEnd) return null;
     if (inStart > inEnd) return null;
 ​
     // 打印二叉树的重建日志
     System.out.println("~~~~~~~~~~~~~~~~~~~~~~~");
     System.out.println("preStart: " + preStart + ", preEnd: " + preEnd);
     System.out.println("inStart: " + inStart + ", inEnd: " + inEnd);
 ​
     // 前序遍历中的第一个元素就是根结点
     int value = preList[preStart];
     BinaryTreeNode node = new BinaryTreeNode();
     node.value = value;
 ​
     System.out.println("value: " + value);
 ​
     // 从中序遍历中查找该值所在索引
     int idx = inStart;
     for (int i = inStart; i <= inEnd; i++) {
         if (inList[i] == value) {
             idx = i;
             break;
         }
     }
 ​
     System.out.println("value: " + value + ", idx: " + idx);
 ​
     // 递归
     // 构建左子树
     node.left = recreateBinaryTree(preList, preStart + 1, preStart + idx - inStart, inList, inStart, idx - 1);
 ​
     // 构建右子树
     node.right = recreateBinaryTree(preList, preStart + idx - inStart + 1, preEnd, inList, idx + 1, inEnd);
 ​
     return node;
 }
复制代码

扩展

二叉树的前序遍历

思路: 先访问该结点本身, 再访问该结点的左子树, 最后访问该结点的右子树

 public void inOrder(BinaryTreeNode node) {
     if (node == null) return;
     inOrder(node.left);
     System.out.print(node.value + "");
     inOrder(node.right);
 }
复制代码

二叉树的中序遍历

思路: 先访问一个结点的左子树, 再访问该结点本身, 最后访问该结点的右子树

 public void inOrder(BinaryTreeNode node) {
     if (node == null) return;
     inOrder(node.left);
     System.out.print(node.value + "");
     inOrder(node.right);
 }
复制代码

二叉树的后序遍历

思路: 先访问一个结点的左子树, 再访问该结点的右子树, 最后访问结点本身

 public void postOrder(BinaryTreeNode node) {
     if (node == null) return;
     postOrder(node.left);
     postOrder(node.right);
     System.out.print(node.value + "");
 }
复制代码

二叉树的层次遍历

思路: 利用队列, 实现二叉树的层次遍历

  1. 先将根结点入队
  2. 从队列中取出结点, 先访问该结点中的值, 再判断该结点是否有左右子结点, 如果有则入队, 否则不入队
  3. 直到队列为空, 则也代表了二叉树已经遍历完毕
 public void levelOrder(BinaryTreeNode node) {
     if (node == null) return;
 ​
     // 创建一个队列
     Queue<BinaryTreeNode> list = new java.util.LinkedList<>();
     
     // 将根结点入队
     list.add(node);
 ​
     // 如果队列不为空
     while (!list.isEmpty()) {
         
         // 则从队列中取出一个结点
         BinaryTreeNode pollNode = list.poll();
         System.out.print(pollNode.value + " ");
         
         // 如果结点有左子结点, 则将该结点入队
         if (pollNode.left != null) list.offer(pollNode.left);
 ​
         // 如果结点有右子结点, 则将该结点入队
         if (pollNode.right != null) list.offer(pollNode.right);
     }
 }
复制代码

总结

初见这个问题时, 脑海一片空白. 只有静下以来, 充分分析二叉树的各种遍历的特点, 才能找到解决问题的方法.

在解题的过程中, 我们把构建二叉树的大问题, 分解成构建二叉树的左右子树的问题. 然后发现它们的本质是一样的, 因此我们想到了用递归方式解决.

在碰到自己没有头绪的问题时, 我们要躺平, 睡一会儿, 何必要跟自己过不去呢?

猜你喜欢

转载自juejin.im/post/7017700865356070925