資料結構之你真的瞭解二叉樹嗎

獼猴桃女孩發表於2020-11-18

簡述

你真的瞭解二叉樹嗎?
一棵二叉樹是結點的一個有限集合,該集合或者為空,或者是由一個根節點加上兩棵別稱為左子樹和右子樹的二叉樹組成。
這是表面上的二叉樹,本文將基於二叉樹的前中後序遍歷解決一些求解二叉樹的相關問題,感興趣的就繼續往下看吧。

定義二叉樹的結點

二叉樹是結點的有限集合,那麼結點就必不可少啦:

public class TreeNode {
    public TreeNode left;
    public TreeNode right;
    public int value;

    public TreeNode(int value) {
        this.value = value;
    }
}

二叉樹的前中後序遍歷

二叉樹的前中後序遍歷運用了遞迴的方法,根結點單獨考慮,然後對左右子樹採用相同的方法:

public class TreeTraversal {
    //前序遍歷
    public static void preTraversal(Node root){
        if(root!=null) {
            System.out.printf("%c",root.val);
            preTraversal(root.left);
            preTraversal(root.right);
        }else{
            //不處理
        }
    }

    //中序遍歷
    public static void inTraversal(Node root){
        if(root!=null){
            inTraversal(root.left);
            System.out.printf("%c",root.val);
            inTraversal(root.right);
        }else{}
    }

    //後序遍歷
    public static void postTraversal(Node root){
        if(root!=null){
            postTraversal(root.left);
            postTraversal(root.right);
            System.out.printf("%c",root.val);
        }else{}
    }
}

你品,你細品,這方法是不是很巧妙,那麼接下來,別眨眼,套路他這就來了…

計算結點個數

計算二叉樹結點的個數

public static int sumNodeSize(Node root){
        if(root==null){
            return 0;
        }else {
            int rootNodeSize = 1;//根結點單獨考慮
            //對左右子樹採用相同的方法
            int leftNodeSize = sumNodeSize(root.left);
            int rightNOdeSize = sumNodeSize(root.right);
            return rootNodeSize + leftNodeSize + rightNOdeSize;
        }
    }

第k層結點個數

求二叉樹第k層結點個數

public static int sumKlevelNodeSize(TreeNode root,int k){
        //根結點單獨考慮
        if(root==null){
            return 0;
        }else if(k==1){
            return 1;
        }else{
            //對左右子樹採用相同的方法
            int leftsumk_1=sumKlevelNodeSize(root.left,k-1);
            int rightsumk_1=sumKlevelNodeSize(root.right,k-1);
            return leftsumk_1+rightsumk_1;
        }
    }

二叉樹的高度

給定一棵二叉樹,求它的高度:

public static int getHeight(TreeNode root){
        //根結點單獨考慮
        if(root==null){
            return 0;
        }else if(root.left==null&&root.right==null){
            return 1;
        }else{
            //對左右子樹採用相同的方法
            int leftheight=getHeight(root.left);
            int rightheight=getHeight(root.right);
            return Math.max(leftheight,rightheight)+1;
        }
    }

是否有結點值為v

給定一棵二叉樹,給定一個值,判斷二叉樹中是否包含值為指定值的結點:

public static boolean contains(TreeNode root,int v){
        //根結點單獨考慮
        if(root==null){
            return false;
        }else if(root.value==v){
            return true;
        }else{
            //對左右子樹採用相同的方法
            boolean leftCon=contains(root.left,v);

            if(leftCon){
                return true;
            }else {
                boolean rightCon=contains(root.right,v);
                if(rightCon){
                    return true;
                }else{
                    return false;
                }
            }
        }
    }

怎麼樣是不是很驚喜,我連註釋的文案都沒改呢。
下面再奉上一些相關面試題,裡面也有相關應用,入股不虧!

平衡二叉樹

輸入一棵二叉樹的根節點,判斷該樹是不是平衡二叉樹。如果某二叉樹中任意節點的左右子樹的深度相差不超過1,那麼它就是一棵平衡二叉樹。
此處提供一種思路:求結點左右子樹高度再通過高度差判斷是否為平衡二叉樹。

public class balanceTreeJZ55 {
    public boolean isBalanced(TreeNode root) {
        //單獨考慮根結點
        if(root==null){
            return true;
        }
        //用到剛才求高度的方法
        int lefth=getHeight(root.left);
        int righth=getHeight(root.right);
        int dif=lefth-righth;
        //判斷高度差是否<=1
        if(!(dif==-1||dif==0||dif==1)){
            return false;
        }
        //對左右子樹採用相同的方法 得到的結果結合得出最終結果
        return isBalanced(root.left)&&isBalanced(root.right);
    }

    private int getHeight(TreeNode root) {
        if(root==null){
            return 0;
        }
        return Math.max(getHeight(root.right),getHeight(root.left))+1;
    }
}

另一個樹的子樹

給定兩個非空二叉樹 s 和 t,檢驗 s 中是否包含和 t 具有相同結構和節點值的子樹。s 的一個子樹包括 s 的一個節點和這個節點的所有子孫。s 也可以看做它自身的一棵子樹。

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/subtree-of-another-tree
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

此處提供一種思路:如果s為空樹,那麼一定返回false,如果s跟q的值相等,那麼需要單獨判斷他們兩是否為相同的樹,相同的話,就返回true,不相同繼續判斷,最後,繼續判斷左子樹右子樹是否包含就可以了。

public class isSonTree572 {
    //判斷是否為相同樹
    public boolean isSameTree(TreeNode p, TreeNode q) {
        //兩者皆為空樹
        if(p==null&&q==null){
            return true;
        }
        //有一個是空樹
        if(p==null||q==null){
            return false;
        }
        //根結點相等並且左右子樹也互為相同樹 
        return p.value==q.value&&isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
    }

    public boolean isSubtree(TreeNode s, TreeNode t) {
        //s為空時
        if(s==null){
            return false;
        }
        //根結點就相等時
        if(s.value==t.value){
            if(isSameTree(s,t)){
                return true;
            }
        }
        //通過對左右子樹採用相同的方法  判斷左右子樹是否有該子樹
        if(isSubtree(s.left,t)){
            return true;
        }
        return isSubtree(s.right,t);
    }
}

二叉樹的最近公共祖先

給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。

百度百科中最近公共祖先的定義為:“對於有根樹 T 的兩個結點 p、q,最近公共祖先表示為一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

此處提供一種方法,當兩個結點都在左子樹中那麼最近公共祖先也在裡面(右同),如果一個在左子樹,一個在右子樹那麼最近公共祖先就是根結點。需要單獨寫一個方法判斷結點是在左子樹還是右子樹,詳見程式碼:

public class nearestAncestor236 {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        //根結點單獨考慮
        if(p==root||q==root){
            return root;
        }
        //對左右子樹採用相同的方法
        boolean pInleft=search(root.left,p);
        boolean qInleft=search(root.left,q);

        //兩個結點都在左子樹
        if(pInleft&&qInleft){
            return lowestCommonAncestor(root.left,p,q);
        }
        //兩個結點都在右子樹
        else if(!pInleft&&!qInleft){
            return lowestCommonAncestor(root.right,p,q);
        }

        //一個在左 一個在右 最近祖先為根結點
        else{
            return root;
        }
    }

    //單獨寫一個方法判斷結點在左子樹還是右子樹 即判斷以root為跟的子樹裡是否有t結點
   private boolean search(TreeNode root, TreeNode t) {
        //根為空
        if(root==null){
            return false;
        }
        //跟結點就是
        if(root==t){
            return true;
        }
        //對左右子樹採用相同的方法
        return search(root.left,t)||search(root.right,t);
    }
}

好啦,看了這麼多題目是不是有暈,反正小編是有點腦殼疼了,慢慢消化吧,我們下期再見,如有誤之處還請批評指正。

相關文章