樹結構

  1. 樹的基本概念

    除了根節點之外每個結點只有一個父節點,根節點沒有父節點;除了葉子節點,所有節點都有一個或多個子節點,葉子節點沒有子節點。

    二叉樹
    在二叉樹中每個節點最多隻有兩個子節點

    二叉樹的性質
    a. 在非空二叉樹的k層上,至多有2^(k-1)個節點(k>=1)
    b. 高度爲k的二叉樹中,最多有2^k-1個節點(k>=1)
    c. 對於任何一棵非空的二叉樹,如果葉節點個數爲n0,度數爲2的節點個數爲n2,則有: n0 = n2 + 1

    完全二叉樹性質:

    除最後一層外,每一層上的節點數均達到最大值;在最後一層上只缺少右邊的若干結點

    a. 具有n個節點的完全二叉樹的高度k爲[log2n]
    b. 對於具有n個節點的完全二叉樹,如果按照從上(根節點)到下(葉節點)和從左到右的順序 對二叉樹中的所有節點從0開始到n-1進行編號,則對於任意的下標爲k的節點,有:

    如果k=0,則它是根節點,它沒有父節點;如果k>0,則它的父節點的下標爲[(i-1)/2];
    如果2k+1 <= n-1,則下標爲k的節點的左子結點的下標爲2k+1;否則,下標爲k的節點沒有左子結點.
    如果2k+2 <= n-1,則下標爲k的節點的右子節點的下標爲2k+2;否則,下標爲k的節點沒有右子節點

滿二叉樹

除最後一層無任何子節點外,每一層上的所有結點都有兩個子結點或0個子節點的二叉樹。
在滿二叉樹中,葉節點的個數比分支節點的個數多1

  1. 二叉樹的遍歷

(1)前序遍歷
a:非遞歸

/**
     * 二叉樹的前序遍歷  非遞歸方式
     * 算法思想:
     * (1)若當前節點不爲空,則輸出當前節點,並把該節點壓入棧,如果當前節點左子樹不爲空,指向左子樹,
     *    
     * (2)若當前節點爲空,但棧不爲空,讀取並刪除棧頂元素,指向棧頂元素的右節點,依次循環
     * @param root
     */
    public static void preOrder_notrec(TreeNode root){
        //定義棧,用來存放節點
        Stack<TreeNode> s=new Stack<TreeNode>();

        while(root!=null || !s.empty()){
            if(root!=null ){
                System.out.println(root.val);
                s.push(root);
                root=root.left;
            }else{
                root=(TreeNode) s.pop();
                root=root.right;
                }
            }
    }
b:遞歸
/**
     * 二叉樹的前序遍歷 遞歸方式
     * @param root
     */
    public static void preOrder_rec(TreeNode root){
        if(root!=null){
            System.out.println(root.val);
            if (root.left!=null)
                preOrder_rec(root.left);
            if(root.right!=null)
                preOrder_rec(root.right);
        }
    }

(2)中序遍歷
a:非遞歸

/**
     * 二叉樹的中序遍歷的非遞歸實現方式
     * 算法思路:
     * 
     * @param root
     */
    public static void midOrder_notrec(TreeNode root){
        //定義棧,用來存放節點
        Stack<TreeNode> s=new Stack<TreeNode>();

        while(root!=null || !s.empty()){
            if(root!=null ){
                s.push(root);
                root=root.left;
            }else{
                root=(TreeNode) s.pop();
                System.out.println(root.val);
                root=root.right;
                }
            }
    }

b:遞歸


    /**
     * 二叉樹的中序遍歷 遞歸方式
     * @param root
     */
    public static void midOrder_rec(TreeNode root){
        if(root!=null){
            if (root.left!=null)
                preOrder_rec(root.left);
            System.out.println(root.val);
            if(root.right!=null)
                preOrder_rec(root.right);
        }
    }

(3) 後序遍歷
a:非遞歸

/**
     * 二叉樹的後序遍歷的非遞歸實現方式
     * 算法思路:
     * 
     * @param root
     */
    public static void postOrder_notrec(TreeNode root){

        Stack<TreeNode> s = new Stack<TreeNode>();//定義棧,用來存放節點

        TreeNode p = root;//pre標記最近出棧的節點,用於判斷是否是p節點的右孩子,如果是的話,就可以訪問p節點

        TreeNode pre = p;//flag標記是出棧還是繼續將左孩子進棧

        boolean flag = true;
        while(p!=null || !s.isEmpty()) {
           if(p!=null  && flag) {
            s.push(p);
            p = p.left;
           }else 
           {
            if(s.isEmpty()) return;
            p = (TreeNode)s.peek();
                if(p.right != null && p.right!=pre) {
                    p = p.right;
                    flag = true;
                }else {
                    p = (TreeNode)s.pop();
                    System.out.println(p.val);;
                    flag = false;
                    pre = p;
                }
           }
          }
    }

b:遞歸

/**
     * 二叉樹的後序遍歷 遞歸方式
     * @param root
     */
    public static void postOrder_rec(TreeNode root){
        if(root!=null){
            if (root.left!=null)
                preOrder_rec(root.left);
            if(root.right!=null)
                preOrder_rec(root.right);
            System.out.println(root.val);
        }
    }

3:已知二叉樹的前序遍歷和中序遍歷,求該二叉樹結構

/**
     * 已知二叉樹的前序遍歷和後序遍歷,重新構造該二叉樹
     * 並返回根節點
     * @param preOrder
     * @param begin 根節點開始的地方:從1開始
     * @param inOrder 
     * @param end   該子樹結束的地方:起始節點從1開始
     * @param len  該樹的長度
     * @param root  
     * @return
     */
    public static TreeNode ReBuild(String preOrder,int begin,String inOrder, int end,int len){
        if(preOrder==null || preOrder.length()==0 || inOrder==null || inOrder.length()==0
                || len<=0){
            return null;
        }
        //簡歷根節點
        /*int和char的轉換可能跟char是寬度爲16位的實體,用utf-8編碼有關係*/
        /*方法1:要通過Character的getNumericValue方法把char類型轉換爲int類型*/
        TreeNode root=new TreeNode(Character.getNumericValue(preOrder.charAt(begin-1)));
        /*方法2:或者先把char轉換爲String,再講String轉換爲int*/
        //int temp=Integer.parseInt((String.valueOf(preOrder.charAt(begin-1))));

        //遞歸終結條件:子樹只有一個節點
        if(len==1){
            return root;
        }

        //分拆子樹的左子樹和右子樹  
        int i=0;
        while(i<len){
            if(preOrder.charAt(begin-1)==inOrder.charAt(end-i))
                break;
            i++;
        }

        //建立子樹的左子樹  
        root.left=ReBuild(preOrder,begin+1,inOrder,end-i-1,len-1-i);
        //建立子樹的右子樹  
        root.right=ReBuild(preOrder,begin+len-i,inOrder,end,i);
        return root;

    }
/**
     * 已知二叉樹的前序遍歷和中序遍歷,確定二叉樹
     * @param preOrder
     * @param start  開始的節點位置:起始節點從0開始
     * @param inOrder  
     * @param end  結束的位置,起始節點從0開始
     * @param len  樹的節點個數
     * @param root
     * @return
     */
    public static TreeNode buildTree(char[] preOrder, int start,  
            char[] inOrder, int end, int length){
        if (preOrder == null || preOrder.length == 0 || inOrder == null  
                || inOrder.length == 0 || length <= 0) {  
            return null;  
        }  

        //確定根節點
        char value = preOrder[start];  

        TreeNode root = new TreeNode(value);  
        System.out.println(root.val);

        //跳出循環條件:只有一個節點時
        if (length == 1)  
            return root;  

        //確定左右子樹
        int i = 0;  
        while (i < length) {  
            if (value == inOrder[end - i]) {  
                break;  
            }  
            i++;  
        }  

        //左子樹
        root.left = buildTree(preOrder, start + 1, inOrder, end - i - 1, length - 1 - i);  
        //右子樹  
        root.right = buildTree(preOrder, start + length - i, inOrder, end, i );  

        return root;  
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章