[java]二叉樹構建、遍歷、深度、平衡性

VictorLeeLk發表於2017-08-27
package tree;

/**
 * 2017-3-15
 * 劍指offer-P55
 * @author victorlee
 *
 */
public class ConstructTree{
    public Tree construct(int[] pre,int[] in){
        if(pre.length ==0 || in.length == 0)
            return null;
        Tree head = buildTree(pre,0,pre.length-1,in,0,in.length-1);
        return head;
    }
    /**
     * 通過   前序遍歷和中序遍歷重建二叉樹
     * @param preOrder
     * @param begin1
     * @param end1
     * @param inOrder
     * @param begin2
     * @param end2
     * @return
     */
    public Tree buildTree(int[] preOrder, int begin1, int end1, int[] inOrder, int begin2, int end2) {
    // TODO Auto-generated method stub
        if(begin1>end1||begin2>end2){
            return null;
        }
        int rootData = preOrder[begin1];//前序的第一個數字總是樹的根節點包含的數值
        Tree head = new Tree(rootData);//初始化樹的根節點
        int divider = findIndexInArray(inOrder,rootData,begin2,end2);//找到根節點的值在中序遍歷陣列中的位置(索引下標)
        int offSet = divider -begin2 -1;//在中序遍歷陣列中,左子樹最後一個結點的下標

        Tree left = buildTree(preOrder,begin1+1,begin1+1+offSet,inOrder,begin2,begin2+offSet);
        Tree right = buildTree(preOrder,begin1+offSet+2,end1,inOrder,divider+1,end2);
        head.left_child = left;
        head.right_child = right;   
        return head;
    }
    private int findIndexInArray(int[] a, int x, int begin, int end) {
        // TODO Auto-generated method stub
        for(int i = begin;i<=end;i++){
            if(a[i]==x)
                return i;
        }
        return -1;
    }
    public void inOrder(Tree n){
        if(n!=null){
            inOrder(n.left_child);
            System.out.print(n.val+" ");
            inOrder(n.right_child);
        }
    }
    public void preOrder(Tree n){
        if(n!=null){
            System.out.print(n.val+" ");
            preOrder(n.left_child);
            preOrder(n.right_child);
        }
    }
    public void behindOrder(Tree n){
        if(n!= null){
            behindOrder(n.left_child);
            behindOrder(n.right_child);
            System.out.print(n.val+" ");
        }
    }
    /**
     * 遞迴求得樹的深度
     * @param head
     * @return
     */
    public int treeDepth(Tree head){
        if(head == null)
            return 0;
        int nLeft = treeDepth(head.left_child);
        int nRight = treeDepth(head.right_child);
        return (nLeft > nRight)?(nLeft +1):(nRight +1);
    }
    /**
     * 2017-3-17
     * 使用遞迴的方法判斷一棵樹是不是平衡二叉樹
     * 缺點:一個結點會被多次遍歷。
     * @param args
     */
    public boolean isBanlanced(Tree root){
        if(root == null){
            return true;
        }
        int left = treeDepth(root.left_child);
        int right = treeDepth(root.right_child);
        int diff = left -right;
        if(diff>1||diff<-1){
            return false;
        }
        return isBanlanced(root.left_child)&&isBanlanced(root.right_child);
    }
    /**
     * 2017-3-17
     * 一個結點只需要遍歷一次就可以求得該二叉樹是不是平衡二叉樹
     * @param root
     * @param depth
     * @return
     */
    public boolean isBalanced(Tree root,int depth){
        if(root == null){
            depth = 0;
            return true;
        }
        int left=0,right=0;
        if(isBalanced(root.left_child,left)&&isBalanced(root.right_child,right)){
            int diff = left-right;
            if(diff<=1 &&diff>=-1){
                depth = 1+(left>right?left:right);
                return true;
            }
        }
        return false;
    }
    //優化後的方法:一方面可以在計算左右子樹的高度時,判斷是否為平衡二叉樹。
    public boolean isBalanced3(Tree root){
        return getHeight(root)!=-1;
    }
    private int getHeight(Tree root){
        if(root==null) return 0;
        int nLeft=getHeight(root.left_child);
        if(nLeft==-1) return -1;
        int nRight=getHeight(root.right_child);
        if(nRight==-1) return -1;
        if(nLeft-nRight<-1||nLeft-nRight>1)
            return -1;
        return 1+(nLeft>nRight?nLeft:nRight);
    }
    public static void main(String[] args){
        ConstructTree build =new ConstructTree();
        int[] preOrder = {1,2,4,7,3,5,6,8};
        int[] inOrder = {4,7,2,1,5,3,8,6};
        Tree root = build.construct(preOrder, inOrder);

        System.out.print("前序遍歷為:");
        build.preOrder(root);//檢驗構建的二叉樹前序遍歷是否正確
        System.out.println();
        System.out.print("中序遍歷為:");
        build.inOrder(root);//檢驗構建的二叉樹中序遍歷是否正確
        System.out.println();
        System.out.print("後序遍歷為:");
        build.behindOrder(root);
        System.out.print("樹的深度為:");
        int treeDepth = build.treeDepth(root);
        System.out.println(treeDepth);
    }   
}

相關文章