本文的一些图片, 资料 截取自编程之美
对于树的相关问题, 递归是非常常见的
对于第一个问题 : 可以通过先递归获取每一个结点的最大左子树的深度, 以及最大右子树的深度, 然后在递归一次获取(node.maxLeft + node.maxRight)的最大值即为所求
对于第二个问题, 因为我们现在有一个先序, 中序的遍历序列, 所以我们可以确定root结点即为先序遍历的第一个结点, 然后根据中序序列来确定root结点的左右子树, 然后在递归建树即可
对于第三个问题 , 通常是使用一个队列来维护需要遍历的结点队列, 遍历一个结点之后, 就将其左右孩子结点添加到队列中, 遍历啊遍历, 直到队列为空
对于上面的描述, 可能比较抽象, 下面是几幅图, 希望可以帮助理解
问题一 :
1 给定的树
2 递归获取树的最大左右子树深度
3 递归获取树的结点最大距离
问题二 :
1 前序和中序
firstOrder :
infixOrder :
2 判断根节点, 左右子树
根据firstOrder判断根节点 :
根据中序判断左右子树 :
在根据左右子树的节点数, 分解前序中的左右子树 :
确定左右子树的前序, 中序遍历序列之后, 即可递归建树了
问题三 :
1 给定的树
2 将当前结点的左右结点添加到队列, 进队的顺序
进队的顺序就保证了层次关系, 因而层次遍历二叉树得以实现
备注 : 先序构建树, “#“结点表示空节点, 上面的问题三的图形对应的数的表示为 : a b # d # # c f # # e # #
代码清单 :
1 先序建树
2 先序 + 中序, 中序 + 后序, 重建二叉树 [一种思路是上面的思路, 另一种思路是先补全其先序序列[加上空结点], 然后在利用先序建树(1)[注意 : 中序 + 后序重建树, 需要先构建右子树, 然后在构建左子树 ], 不过原理和第一种基本上一致 ]
3 判断给定的先序 + 中序, 是否能够构建一颗二叉树
4 获取指定层级的结点
5 层次遍历, 层次自底向上遍历二叉树
/*** file name : Test09FindMaxDisInBinaryTree.java* created at : 8:56:46 AM May 29, 2015* created by 970655147*/package com.hx.test04;public class Test09FindMaxDisInBinaryTree {// 1. 获取一颗二叉树的两个节点的最大距离// 2. 重建二叉树// 3. 判断给定的(前序, 中序)[(中序, 后序) ] 是否能够成一个合法的二叉树// 4. 获取二叉树的某一层的元素// 5. 顺序遍历二叉树 层次遍历二叉树public static void main(String []args) {// BinTree bt = BinTree.createABinTree();
// Log.log(bt);// -----------获取一颗二叉树的两个节点的最大距离--------------- String data = "58 34 12 # # 42 # # 78 68 69 # # # 99 # #";BinTree bt = BinTree.createABinTree(data);Log.log(bt);List
// BinTree bt02 = BinTree.rebuildForFirstOrderAndInfixOrder02(firstOrder, infixOrder);
// BinTree bt02 = BinTree.rebuildForInfixOrderAndEpilogue(infixOrder, epilogue);BinTree bt02 = BinTree.rebuildForInfixOrderAndEpilogue02(epilogue, infixOrder);Log.log(bt02);// -----------判断给定的(前序, 中序)[(中序, 后序) ] 是否能够成一个合法的二叉树--------------- String[] first = firstOrder.split("\\s+");String[] infix = infixOrder.split("\\s+");Log.log(BinTree.canCompleteForFirstOrderAndInfixOrder(first, infix, 0, 0, first.length) );// -----------获取二叉树的某一层的元素---------------BinTree.getSpecifiedLayerElements(bt.root, 2);Log.enter();// -----------顺序遍历二叉树 层次遍历二叉树---------------BinTree.traverseInOrder(bt.root);BinTree.traverseInOrder02(bt.root);BinTree.traverseInOrderInversely(bt.root);BinTree.traverseInOrderInversely02(bt.root);// -----------splits---------------}// 一颗二叉树public static class BinTree {// 根节点Node root;// 初始化public BinTree() {root = new Node();}public BinTree(Node root) {this.root = root;}// 获取root节点public Node root() {return root;}// 判断结点的左结点是否为空[#也算为空]public static boolean isNodeNull(Node node) {return (node == null) || (Node.NULL.equals(node.getData()) );}// 根据用户的输入创建一颗二叉树public static BinTree createABinTree() {BinTree bt = new BinTree();createNode(bt.root, "root");return bt;}// 根据指定格式的字符串创建一颗二叉树public static BinTree createABinTree(String data) {return createABinTreeReversely(data);}// 根据指定格式的字符串创建一颗二叉树 先建立左子树 在建立右子树public static BinTree createABinTreeReversely(String data) {BinTree bt = new BinTree();String[] splits = data.split("\\s+");idx = 0;createNodeReversely(bt.root, splits);return bt;}// 根据指定格式的字符串创建一颗二叉树 先建立右子树 在建立左子树public static BinTree epilogueOrderCreateABinTreeInversely(String data) {BinTree bt = new BinTree();String[] splits = data.split("\\s+");idx = 0;epilogueOrderCreateNodeInversely(bt.root, splits);return bt;}// assistMethod 根据用户的输入建树private static void createNode(Node node, String notice) {Scanner scan = Tools.getScanner();Log.logWithoutLn("please input " + notice + " : ");node.data = scan.next();if(!Node.NULL.equals(node.data) ) {node.left = new Node();node.right = new Node();createNode(node.left, notice + "'s leftChild");createNode(node.right, notice + "'s rightChild");}}// assistMethod 根据指定格式的字符串建树static int idx;// 先建立左子树 在建立右子树private static void createNodeReversely(Node node, String[] data) {node.data = data[idx ++];if(!Node.NULL.equals(node.data) ) {node.left = new Node();node.right = new Node();createNodeReversely(node.left, data);createNodeReversely(node.right, data);}}// 先建立右子树 在建立左子树private static void epilogueOrderCreateNodeInversely(Node node, String[] data) {node.data = data[idx ++];if(!Node.NULL.equals(node.data) ) {node.left = new Node();node.right = new Node();epilogueOrderCreateNodeInversely(node.right, data);epilogueOrderCreateNodeInversely(node.left, data);}}// 根据先序, 中序 重新建树// 思路 : 先补全树的字符串表示, 在建树[左 -> 右]public static BinTree rebuildForFirstOrderAndInfixOrder(String firstOrder, String infixOrder) {String[] first = firstOrder.split("\\s+");String[] infix = infixOrder.split("\\s+");StringBuilder sb = new StringBuilder();completeForFirstOrderAndInfixOrder(first, infix, 0, 0, first.length, sb);return createABinTree(sb.toString());}// 根据先序, 中序 重新建树 递归建树public static BinTree rebuildForFirstOrderAndInfixOrder02(String firstOrder, String infixOrder) {String[] first = firstOrder.split("\\s+");String[] infix = infixOrder.split("\\s+");Node root = rebuildForFirstOrderAndInfixOrder020(first, infix, 0, 0, first.length);return new BinTree(root);}// 根据中序, 后序 重新建树// 思路 : 先补全树的逆序字符串表示, 在逆序建树[右 -> 左]public static BinTree rebuildForInfixOrderAndEpilogue(String infixOrder, String epilogueOrder) {String[] epilogue = epilogueOrder.split("\\s+");String[] infix = infixOrder.split("\\s+");StringBuilder sb = new StringBuilder();completeForInfixOrderAndEpilogue(epilogue, infix, 0, 0, epilogue.length, sb);return epilogueOrderCreateABinTreeInversely(sb.toString());}// 根据先序, 中序 重新建树 递归建树public static BinTree rebuildForInfixOrderAndEpilogue02(String epilogueOrder, String infixOrder) {String[] epilogue = epilogueOrder.split("\\s+");String[] infix = infixOrder.split("\\s+");Node root = rebuildForInfixOrderAndEpilogueOrder020(epilogue, infix, 0, 0, infix.length);return new BinTree(root);}// 根据先序和中序 补全 "#"子节点private static void completeForFirstOrderAndInfixOrder(String[] first, String[] infix, int start01, int start02, int len, StringBuilder sb) {sb.append(first[start01] + " ");int idx = getIdxForStr(first[start01], infix, start02, len);int leftNumMinus1 = idx - start02, rightNumMinus1 = start02 + len - idx - 1;if(leftNumMinus1 == 0) {sb.append("# ");} else {completeForFirstOrderAndInfixOrder(first, infix, start01+1, start02, leftNumMinus1, sb);}if(rightNumMinus1 == 0) {sb.append("# ");} else {completeForFirstOrderAndInfixOrder(first, infix, start01+leftNumMinus1+1, idx+1, rightNumMinus1, sb);}}// 根据先序和中序, 递归构造左右子树private static Node rebuildForFirstOrderAndInfixOrder020(String[] first, String[] infix, int start01, int start02, int length) {Node node = new Node(first[start01]);int idx = getIdxForStr(first[start01], infix, start02, length);int leftNumMinus1 = idx - start02, rightNumMinus1 = start02 + length - idx - 1;if(leftNumMinus1 > 0) {node.left = rebuildForFirstOrderAndInfixOrder020(first, infix, start01+1, start02, leftNumMinus1);} else {node.left = new Node(Node.NULL);}if(rightNumMinus1 > 0) {node.right = rebuildForFirstOrderAndInfixOrder020(first, infix, start01+1+leftNumMinus1, idx+1, rightNumMinus1);} else {node.right = new Node(Node.NULL);}return node;}// 根据先序和中序 补全 "#"子节点private static void completeForInfixOrderAndEpilogue(String[] epilogue, String[] infix, int start01, int start02, int len, StringBuilder sb) {int endIdx = start01 + len - 1;sb.append(epilogue[endIdx] + " ");int idx = getIdxForStr(epilogue[endIdx], infix, start02, len);int leftNumMinus1 = idx - start02, rightNumMinus1 = start02 + len - idx - 1;if(rightNumMinus1 == 0) {sb.append("# ");} else {completeForInfixOrderAndEpilogue(epilogue, infix, endIdx-rightNumMinus1, idx+1, rightNumMinus1, sb);}if(leftNumMinus1 == 0) {sb.append("# ");} else {completeForInfixOrderAndEpilogue(epilogue, infix, start01, start02, leftNumMinus1, sb);}}// 根据中序和后序, 递归构造左右子树private static Node rebuildForInfixOrderAndEpilogueOrder020(String[] epilogue, String[] infix, int start01, int start02, int length) {int endIdx = start01 + length - 1;Node node = new Node(epilogue[endIdx]);int idx = getIdxForStr(epilogue[endIdx], infix, start02, length);int leftNumMinus1 = idx - start02, rightNumMinus1 = start02 + length - idx - 1;if(rightNumMinus1 > 0) {node.right = rebuildForInfixOrderAndEpilogueOrder020(epilogue, infix, start01+leftNumMinus1, idx+1, rightNumMinus1);} else {node.right = new Node(Node.NULL);}if(leftNumMinus1 > 0) {node.left = rebuildForInfixOrderAndEpilogueOrder020(epilogue, infix, start01, start02, leftNumMinus1);} else {node.left = new Node(Node.NULL);}return node;}// 判断给定的前序和中序 是否合理 是否能构成一颗合法的二叉树public static boolean canCompleteForFirstOrderAndInfixOrder(String[] first, String[] infix, int start01, int start02, int len) {int idx = getIdxForStr(first[start01], infix, start02, len);int leftNumMinus1 = idx - start02, rightNumMinus1 = start02 + len - idx - 1;boolean isLeftOk = false, isRightOk = false;if(leftNumMinus1 == 0) {isLeftOk = true;} else {isLeftOk = canCompleteForFirstOrderAndInfixOrder(first, infix, start01+1, start02, leftNumMinus1);}if(rightNumMinus1 == 0) {isRightOk = true;} else {isRightOk = canCompleteForFirstOrderAndInfixOrder(first, infix, start01+leftNumMinus1+1, idx+1, rightNumMinus1);}return isLeftOk && isRightOk;}// 获取level层的元素 递归实现public static void getSpecifiedLayerElements(Node node, int level) {if(Node.NULL.equals(node.data) ) {return ;}if(level == 0) {Log.logWithoutLn(node.data + " ");}getSpecifiedLayerElements(node.left, level-1);getSpecifiedLayerElements(node.right, level-1);}// 顺序遍历二叉树 方向从左至右public static void traverseInOrder(Node node) {Deque
// sb.append(node.maxLeft + " - " + node.maxRight + "; ");headTraverseForString(node.left, sb);headTraverseForString(node.right, sb);}}// 先序遍历二叉树获取各个叶子节点的深度public void headTraverseForMaxDepth(Node node, int cnt, List
树是一种递归的结构, 所以涉及的算法很多都涉及递归, 通过这几个算法, 相信我们对于二叉树的了解又会深一层