/** * 重建二叉树 ;根据给定的前序和中序遍历的结果,构造出树的结构 */ package binaryBree; import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; /** * @author Amory.Wang * Question : 重建二叉树 * test example : 普通二叉树 , 特殊二叉树(只有右结点或者只有左结点) ,特殊输入测试 : root=null/输入前序和中序不匹配 * 2017年7月28日下午4:27:15 */ class node{ int data; node leftChild; node rightChild; /** * allocate new tree node */ public node(int d) { this.data = d; this.leftChild = null; this.rightChild = null; } } public class ReconstructTree{ public static node returnTree(){ System.out.println("input the preOrder : (please use ',')"); Scanner scan = new Scanner(System.in); String s = scan.next(); String[] sa = s.split(","); int[] preOrder = new int[sa.length]; for(int i=0; i<preOrder.length; ++i){ preOrder[i] = Integer.parseInt(sa[i]); } System.out.println("input the inOrder : "); String s1 = scan.next(); String[] sa1 = s1.split(","); int[] inOrder = new int[sa1.length]; for(int i=0; i<inOrder.length; ++i){ inOrder[i] = Integer.parseInt(sa1[i]); } if(preOrder.length != inOrder.length){ System.out.println("preOrder's number is not equals inOrder's number"); return null; } return constructCore(preOrder, 0, preOrder.length-1, inOrder, 0, inOrder.length-1); } /** * * @param pre : 前序遍历的数组 * @param in : 中序遍历的数组 * @param startPre : 前序的开始节点位置 * @param endPre : 前序的结束节点 * @param startIn : 中序的开始节点位置 * @param endIn : 中序的结束节点位置 * @return : 根节点 */ public static node constructCore(int[] pre, int startPre, int endPre, int[] in, int startIn, int endIn){ if(pre == null || in == null){ System.out.println("root is null !"); return null; } // step 1 : 找到前序的根节点在中序的索引 node root = new node(pre[startPre]); int rootInindex = startIn; while(root.data != in[rootInindex]){ rootInindex ++; } // prepare : 1-1 : 确定左右子树的个数 int leftNodes = rootInindex-startIn; int rightNodes = endIn-rootInindex; // 1-2 : 在前序中根据左右子树的个数确定左右子树的节点分别是哪些 int startLeft = startPre+1; int endLeft = startLeft+leftNodes-1; int startRight = endLeft+1; int endRight = startRight+rightNodes-1; // step 2 : 对于中序中的根节点的位置在结合前序序列中进行左右子树的创建 if(leftNodes <= 0){ // 左子树为空 root.leftChild = null; }else{ root.leftChild = constructCore(pre, startLeft, endLeft, in, startIn, rootInindex-1); } if(rightNodes <= 0){ // 右子树为空 root.rightChild = null; }else{ root.rightChild = constructCore(pre, startRight, endRight, in, rootInindex+1, endIn); } return root; } // step 3 : 进行宽度优先遍历 -- 要用到队列的特征,先进先出 public static StringBuilder borderPrintTree(node root){ StringBuilder widthString = new StringBuilder(); Queue<node> nodeQue = new LinkedList<node>(); if(root != null){ nodeQue.add(root); } while(!nodeQue.isEmpty()){ node popNode = nodeQue.poll(); widthString.append(popNode.data); if(popNode.leftChild != null){ nodeQue.add(popNode.leftChild); } if(popNode.rightChild != null){ nodeQue.add(popNode.rightChild); } } return widthString; } // test public static void main(String[] args) { node root = returnTree(); StringBuilder sb = borderPrintTree(root); System.out.println(sb); } }
总结一下 : 这个递归的过程是逐渐优化的过程,容易搞混的地方主要在于对于前序序列和中序序列的中的参数变化,所以一点很重要,每一步的目的是什么,需要哪些参数来满足需求,搞清楚了之后在写代码.