一,問題描述
給定一棵二叉查找樹,以及某個結點的值。查找該結點的下一個結點。如果該結點是最大的,則返回 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); } }
五,參考資料
