二叉樹進階之尋找一棵二叉樹中的最大二叉搜索子樹


轉載請注明原文地址:http://www.cnblogs.com/ygj0930/p/6618915.html 

    (規律:在二叉樹中尋找某性質信息的題目的解題思路:用后序遍歷從小樹建立大樹,還原二叉樹從底層各棵小樹匯聚成完整樹的過程。在建立過程中對每一棵子樹進行判斷尋找,記錄查找性質的所需信息以及當前子樹的查找結果向上傳遞(結點作返回值,其他信息用數組。由於樹最終會在根結點匯總,那么從子樹中的查找出來的結果就被會傳遞到根結點處了。)

 

    從一棵樹中尋找結點數最多的二叉搜索子樹,並返回這棵子樹的頭結點。

    從題目我們知道以下要求:

    1:子樹是二叉搜索樹,即:左兒子小於父節點,右兒子大於父節點,並且這個性質在整棵樹的任一子樹都成立。——從任一子樹成立,可以得知:一棵二叉搜索子樹的本身,是從它的子樹也是二叉搜索樹遞推上來的。因此,我們在遞歸時,從葉到根逐步建立二叉樹的過程中可以每一步都知道當前“根”的子樹是否滿足二叉搜索樹性質,是則返回這個“根”,否則返回一個兒結點。對建立二叉樹的過程中每一步的當前“根”,我們都假設左右子樹是二叉搜索樹,那么遞歸左子樹時返回的就是左兒子,遞歸右子樹時返回的就是右兒子。因此我們對當前結點作以下判斷:左子樹最大值<當前結點值<右子樹最小值 && 左子樹中的二叉搜索樹根是左兒子 && 右子樹中的二叉搜索樹根是是右兒子,則當前結點為“根”的子樹也是二叉搜索樹,把當前結點返回遞歸上層給他的父節點作判斷使用,否則返回一個兒結點(只要父節點發現遞歸子樹時返回的不是自己的兒子,即可說明以父節點為根的子樹不是二叉搜索樹)。

    2:二叉搜索子樹的結點數最大。一個結點為根的子樹中找結點數最多的二叉搜索子樹,有兩種情況:

    1)當前結點左子樹是二叉搜索樹,當前結點右子樹是二叉搜索樹,並滿足 left_max<curr<right_min,那么以當前結點為根的樹也是二叉搜索樹,更新最大二叉搜索樹的結點數信息,把curr往上傳遞;

    2)如果不滿足第一點,則當前結點為根的結點數最多二叉搜索子樹是它的左右子樹中結點數最大的那個二叉搜索子樹,返回左右子樹中結點數最多的二叉搜索子樹的根結點向上傳遞,更新當前子樹的最大二叉搜索樹的結點數信息。

    3:極限情況下,整棵樹中沒有一棵二叉搜索子樹,那么遞歸到葉子結點的兒結點null時,返回null。然后在逐層向上返回時,因為沒有一棵二叉搜索子樹,所以null被一直向上傳遞返回。最終得到結果就是Null.也就是說:只要有一棵二叉搜索子樹,那么它的“根”結點就會被往上傳遞,作為它的眾多祖先們(包括父親)的子樹中的候選最大二叉搜索子樹直到被拋棄(在某一層時被另一子樹傳上來的最大二叉搜索子樹取代)。

 

    采用后序遍歷的方式來遍歷二叉樹,對每個結點對進行情況1檢查,如果符合則更新子樹最大BST信息(根結點、結點數)並往上傳遞,如果不是則按照情況2處理。

    每層需要采集以下信息:

    1:左子樹中的最大值,左子樹中最小值左子樹的最大二叉搜索子樹的根結點、左子樹中最大二叉搜索子樹的結點數目(從下往上創建的二叉搜索子樹,每處理一個結點若當前結點為根的樹是二叉搜索樹,則結點數目=左子樹結點數+右子樹結點數+1.而左右子樹結點數又是從下往上傳來的,從最底層null傳來的是0,每層往上=左子樹結點數+右子樹結點數+1)【遞歸用到的計數,都是從遞歸邊界開始的!所以寫遞歸時一定要先寫好遞歸邊界的返回情況

    2:右子樹的同樣4樣信息。

    3:多信息采集的遞歸,我們采取“結點作返回值,其他信息用數組”的方法。

    

    public TreeNode getMax(TreeNode root) {
        if(root==null){
            return null;
        }
        //用數組記錄子樹中信息:最大值、最小值、子樹中最大二叉搜索樹的結點數
        int[] childtree_info=new int[3];
        return postfind(root,childtree_info);        
    }
    
    public TreeNode postfind(TreeNode curr,int[] childtree_info){
        //遞歸邊界:null結點。遞歸用到的計數,都是從遞歸邊界開始的!所以寫遞歸時一定要先寫好遞歸邊界的返回情況
        if(curr==null){
            childtree_info[0]=Integer.MIN_VALUE;//Null結點,子樹最大值不存在,所以令為很小值
            childtree_info[1]=Integer.MAX_VALUE;//Null結點,子樹最小值不存在,所以令為很大值
            childtree_info[2]=0;//Null結點的最大二叉搜索子樹結點數為0
            return curr;
        }
        
        //遞歸左右子樹,獲取4個信息
        TreeNode left_maxBST=postfind(curr.left,childtree_info);
        int left_maxBST_max=childtree_info[0];
        int left_maxBST_min = childtree_info[1];
        int left_maxBST_nodesnum = childtree_info[2];       
        TreeNode right_maxBST=postfind(curr.right,childtree_info);
        int right_maxBST_max = childtree_info[0];
        int right_maxBST_min = childtree_info[1];
        int right_maxBST_nodesnum = childtree_info[2];
        
//更新當前結點為根的子樹的最大值、最小值 childtree_info[
0]=Math.max(right_maxBST_max,curr.val); childtree_info[1]=Math.min(left_maxBST_min,curr.val); //根據左右子樹遞歸信息,判斷當前結點為根的子樹性質:如果是二叉搜索樹則更新最大二叉搜索子樹的信息;如果不是,則返回左右子樹中的最大二叉搜索子樹的信息 if(left_maxBST==curr.left && right_maxBST==curr.right && left_maxBST_max<curr.val && curr.val<right_maxBST_min){ childtree_info[2]= left_maxBST_nodesnum + right_maxBST_nodesnum +1; return curr; }else{ childtree_info[2]=Math.max(left_maxBST_nodesnum,right_maxBST_nodesnum); return left_maxBST_nodesnum>right_maxBST_nodesnum?left_maxBST:right_maxBST; } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM