java基础编程——重建二叉树
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
题目代码
/** * Created by YuKai Fan on 2018/8/17. */ public class ReBuildTreeNode { public static void main(String[] args) { ReBuildTreeNode rtn = new ReBuildTreeNode(); int[] pre = {1,2,4,7,3,5,6,8}; int[] in = {4,7,2,1,5,3,8,6}; TreeNode treeNode = rtn.reConstructBinaryTree(pre, in); TreeNode treeNode1 = rtn.reConstructBinaryTree2(pre, 0, pre.length, in, 0, in.length); System.out.println(treeNode.left.val); } /* 分析: 前序遍历:root->left->right 中序遍历:left->root->right 所以根据前序遍历可以得到pre[0]就是二叉树的root根节点,在根据中序遍历集合可以得到,该根节点的左边是左子树,右边是右子树 调用递归,可以将得到的前序和中序左子树集合看成一个新的二叉树,与上方同理,调用递归,而右子树也是同理可得。 方法一: 这个方法使用了数组Arrays的API:copyOfRange(array,i,j)方法,可以从i开始到j(不包括j)复制一个array数组,并产生一个新的数组, 用这种方法可以得到该二叉树的左子树和右子树,在调用递归 */ public TreeNode reConstructBinaryTree(int [] pre,int [] in) { if (pre.length == 0 || in.length == 0) { return null; } TreeNode tn = new TreeNode(pre[0]); for (int i = 0; i < in.length; i++) { if (in[i] == pre[0]) { tn.left = reConstructBinaryTree(Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(in,0,i)); tn.right = reConstructBinaryTree(Arrays.copyOfRange(pre,i+1,pre.length),Arrays.copyOfRange(in,i+1,in.length)); } } return tn; } /* 方法二 */ public TreeNode reConstructBinaryTree2(int [] pre,int sPre, int ePre,int [] in, int sIn, int eIn) { if (sPre > ePre || sIn > eIn) { return null; } TreeNode tn = new TreeNode(pre[sPre]); for (int i = sIn; i < eIn; i++) { if (in[i] == pre[sPre]) { tn.left = reConstructBinaryTree2(pre,sPre+1, sPre+i-sIn,in,sIn,i-1); tn.right = reConstructBinaryTree2(pre,sPre+i-sIn+1,ePre,in,i+1,eIn); } } return tn; } }
/** * Created by YuKai Fan on 2018/8/17. */ public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int val) { this.val = val; } }
题目延伸
二叉树是一种非常重要的数据结构,非常多其他数据结构都是基于二叉树的基础演变而来的。对于二叉树,有深度遍历和广度遍历,深度遍历有前序、中序以及后序三种遍历方法,广度遍历即我们寻常所说的层次遍历。由于树的定义本身就是递归定义,因此採用递归的方法去实现树的三种遍历不仅easy理解并且代码非常简洁,而对于广度遍历来说,须要其他数据结构的支撑。比方堆了。所以。对于一段代码来说,可读性有时候要比代码本身的效率要重要的多。
四种基本的遍历思想为:
前序遍历:根结点 ---> 左子树 ---> 右子树
中序遍历:左子树---> 根结点 ---> 右子树
后序遍历:左子树 ---> 右子树 ---> 根结点
层次遍历:仅仅需按层次遍历就可以
一、前序遍历
依据上文提到的遍历思路:根结点 ---> 左子树 ---> 右子树,递归方法public void preOrderTraverse1(TreeNode root) { if (root != null) { System.out.print(root.val+" "); preOrderTraverse1(root.left); preOrderTraverse1(root.right); } }
二、中序遍历
依据上文提到的遍历思路:左子树 ---> 根结点 ---> 右子树,递归方法
public void inOrderTraverse1(TreeNode root) { if (root != null) { inOrderTraverse1(root.left); System.out.print(root.val+" "); inOrderTraverse1(root.right); } }
三、后序遍历
依据上文提到的遍历思路:左子树 ---> 右子树 ---> 根结点
public void postOrderTraverse1(TreeNode root) { if (root != null) { postOrderTraverse1(root.left); postOrderTraverse1(root.right); System.out.print(root.val+" "); } }
四、层次遍历
层次遍历的代码比較简单。仅仅须要一个队列就可以。先在队列中增加根结点。之后对于随意一个结点来说。在其出队列的时候,訪问之。同一时候假设左孩子和右孩子有不为空的。入队列。代码例如以下:
public void levelTraverse(TreeNode root) { if (root == null) { return; } LinkedList<TreeNode> queue = new LinkedList<>(); queue.offer(root); while (!queue.isEmpty()) { TreeNode node = queue.poll(); System.out.print(node.val+" "); if (node.left != null) { queue.offer(node.left); } if (node.right != null) { queue.offer(node.right); } } }
五、深度优先遍历 事实上深度遍历就是上面的前序、中序和后序。可是为了保证与广度优先遍历相照顾,也写在这。代码也比較好理解,事实上就是前序遍历,代码例如以下:
public void depthOrderTraverse(TreeNode root) { if (root == null) { return; } LinkedList<TreeNode> stack = new LinkedList<>(); stack.push(root); while (!stack.isEmpty()) { TreeNode node = stack.pop(); System.out.print(node.val+" "); if (node.right != null) { stack.push(node.right); } if (node.left != null) { stack.push(node.left); } } }
借鉴的博客:https://www.cnblogs.com/llguanli/p/7363657.html