設計一個算法,找出二叉查找樹中指定結點的「下一個「結點(也即中序後繼)。能夠假定每一個結點都含有指向父結點的鏈接。

問題分析java

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

①node 節點有右孩子算法

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

 

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

 

 

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

 

 

 

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

能夠用先序遍歷的思路。可是必定要注意遞歸的實現---第11行的 return target 是頗有意義的。遞歸

在每一次的遞歸調用中,每一個方法都有一個本身的 target 局部變量。若是在這個方法裏面找到了目標結點,若是沒有 return 返回的話,當遞歸回退時就會丟失「已找到的目標結點」----即上一層的 find 方法中的target 變量仍是null(儘管在下一層遞歸中已經找到了目標結點)get

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

 

複製代碼

 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;
        }

或者:

 

下面是該算法的實現代碼(已正確處理結點爲空的狀況)

public TreeNode inorderSucc(TreeNode n)
{
if(n==null) return null;
/*
找到右子結點,則返回右子樹裏最左邊的結點
*/
if(n.right!=null)
{
return leftMostChild(n.right);
}
else
{
TreeNode q=n;
TreeNode x=q.parent;
//向上直至位於左邊而不是右邊
while(x!=null&&x.left!=q)
{
q=x;
x=x.parent;
}
return x;
}
}


public TreeNode leftMostChild(TreeNode n)
{
if(n==null)
return null;
while(n.left!=null)
{
n=n.left;
}
return null;

}

 

 

或者

相關文章
相關標籤/搜索