尋找二叉查找樹中的下一個結點


一,問題描述

給定一棵二叉查找樹,以及某個結點的值。查找該結點的下一個結點。如果該結點是最大的,則返回 null

對於二叉查找樹而言,它是中序遍歷有序的。某結點的下一個結點 就是:中序遍歷輸出的下一個結點。

 

二,問題分析

假設需要查找 node 結點的下一個結點,需要考慮三種情況:

①node 節點有右孩子

下一個結點就是以node結點的右孩子為根的子樹中的最左下結點。如下圖:node=8,它的下一個結點為12.

 

②node 節點沒有右孩子時,node節點是其父結點的左孩子。如下圖,結點8的下一個結點是結點12

 

 

③node 節點沒有右孩子時,node節點是其父結點的右孩子,如下圖,結點14 的下一個結點是 結點16

 

 

 

如何在一棵二叉樹中查找某個結點?

可以用先序遍歷的思路。但是一定要注意遞歸的實現---第11行的 return target 是很有意義的。

在每一次的遞歸調用中,每個方法都有一個自己的 target 局部變量。如果在這個方法里面找到了目標結點,如果沒有 return 返回的話,當遞歸回退時就會丟失“已找到的目標結點”----即上一層的 find 方法中的target 變量還是null(盡管在下一層遞歸中已經找到了目標結點)

通過第11行的 return 語句,如果在某一層還未找到目標結點,則會繼續遞歸調用下去,如果找到了,在 return 的時候,上一層的find方法的target變量就不會為 null ,  從而在最終 find 方法結束時,返回找到的目標結點。

 

 1     //采用先序遍歷查找值為ele的結點
 2     private BinaryNode find(BinaryNode root, int ele){
 3         if(root == null)
 4             return null;
 5         if(root.ele == ele)
 6             return root;
 7         BinaryNode target = null;
 8         target = find(root.left, ele);
 9         if(target == null)//如果左子樹中沒有值為ele的結點,if成立,在右子樹中查找
10             target = find(root.right, ele);
11         return target;
12     }

①第3-4行是應對查找到葉子結點的情況

②第5-6行,是成功查找到了指定結點的情況。(①②類似於先序遍歷中的訪問根結點)

③第8行,表示先在左子樹中查找(類似於先序遍歷左子樹)

④第9-10行if表示在左子樹中未查找到該結點,則查找右子樹⑤第11行,返回查找的結點。若返回null,表示未找到

 

三,代碼分析

①node 節點有右孩子

1 if(node.right != null)
2 {
3     BinaryNode current = node.right;
4     while(current.left != null)
5     {
6     current = current.left;
7     }
8     nextNode = current;
9  }

第3行,先定位到node結點的右孩子。

第4行while循環,查找最左下結點

 

②node 節點沒有右孩子時,node節點是其父結點的左孩子

1 else if(node.parent != null){//node結點 是 parent 的孩子
2     if(node.parent.left != null && node.parent.left.equals(node))// node 是 parent 的左孩子
3         nextNode = node.parent;

如果node節點是其父結點的左孩子,那么下一個結點就是node節點的父結點。

 

③node 節點沒有右孩子時,node節點是其父結點的右孩子

1 else{//node 是 parent的右孩子
2     BinaryNode current = node.parent;
3     //一直往着右孩子的父結點指針向上走
4     while(current.parent.right != null && current.parent.right.equals(current))
5     {
6         current = current.parent;
7     }
8     nextNode = current.parent;
9 }

要注意第4行while循環中的第一個條件:current.parent.right != null

為什么不要判斷 current.parent != null 呢?因為在前面的if語句中已經判斷了(if(node.parent != null)

 

四,完整代碼實現

public class BSTNextNode {

    private class BinaryNode{
        int ele;
        BinaryNode left;
        BinaryNode right;
        BinaryNode parent;
        int hash;//cache hashCode
        
        public BinaryNode(int ele) {
            this.ele = ele;
            parent = left = right = null;
        }
        
        @Override
        public boolean equals(Object obj) {
            if(obj == null)
                return false;
            if(!(obj instanceof BinaryNode))
                return false;
            BinaryNode node = (BinaryNode)obj;
            return node.ele == this.ele;
        }
        
        @Override
        public int hashCode() {// 參考《effective java》中覆蓋equals方法
            int result = hash;
            if(result == 0){
                result = 17;
                result = result*31 + ele;
                hash = result;
            }
            return result;
        }
        
        @Override
        public String toString() {
            return ele + " "; 
        }
    }
    
    private BinaryNode root;
    
    public void buildTree(int[] eles){
        if(eles == null || eles.length == 0)
            return;
        
        for (int ele : eles) {
            insert(ele);
        }
    }
    private void insert(int ele){
        root = insert(root, ele);
        root.parent = null;
    }
    private BinaryNode insert(BinaryNode root, int ele){
        if(root == null)
            return new BinaryNode(ele);
        if(root.ele > ele){
            root.left = insert(root.left, ele);
            root.left.parent = root;
        }else{
            root.right = insert(root.right, ele);
            root.right.parent = root;
        }
        return root;
    }
    
    //尋找值為ele的那個結點的 下一個結點
    public BinaryNode nextNode(int ele){
        BinaryNode node = find(ele);//找到Node值為ele的結點在BST中的位置
        if(node == null)
            throw new IllegalArgumentException(ele + " not in tree");
        BinaryNode nextNode = null;
        if(node.right != null)
        {
            BinaryNode current = node.right;
            while(current.left != null)
            {
                current = current.left;
            }
            nextNode = current;
        }else if(node.parent != null){//node結點 是 parent 的孩子
            if(node.parent.left != null && node.parent.left.equals(node))// node 是 parent 的左孩子
                nextNode = node.parent;
            else{//node 是 parent的右孩子
                BinaryNode current = node.parent;
                //一直往着右孩子的父結點指針向上走
                while(current.parent.right != null && current.parent.right.equals(current))
                {
                    current = current.parent;
                }
                nextNode = current.parent;
            }
        }else{//node 沒有父結點.那它就是BST中的最大的結點---此時它的下一個結點視為null
//            nextNode = node;
            ;
        }
        return nextNode;
    }
    
    //查找二叉樹中值為ele的結點,並返回該結點
    private BinaryNode find(int ele){
        if(root == null)
            throw new IllegalStateException("bst is null");
        return find(root, ele);
    }
    
    //采用先序遍歷查找值為ele的結點
    private BinaryNode find(BinaryNode root, int ele){
        if(root == null)
            return null;
        if(root.ele == ele)
            return root;
        BinaryNode target = null;
        target = find(root.left, ele);
        if(target == null)//如果左子樹中沒有值為ele的結點,if成立,在右子樹中查找
            target = find(root.right, ele);
        return target;
    }
    
    
    //hapjin test
    public static void main(String[] args) {
//        int[] eles = {20,10,30,15,18,26,22,8,40};
        int ele = 20;
        int[] eles = {20,10,15};
        BSTNextNode bstTree = new BSTNextNode();
        bstTree.buildTree(eles);//構造一棵二叉樹查找樹
        BinaryNode next = bstTree.nextNode(ele);//查找值為ele結點的下一個結點
        System.out.println(next);
    }
}
View Code

 

五,參考資料

二叉樹的構造

 

原文:http://www.cnblogs.com/hapjin/p/5827687.html


免責聲明!

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



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