二叉查詢樹--刪除結點——參考學習
阿新 • • 發佈:2019-01-22
刪除結點
刪除結點存在3種情況,分別為:
1、沒有左右子結點,可以直接刪除
刪除時需要判斷自己和父結點的關係,在左側還是右側
如果父結點的左結點是自己,就清左側,否則清除右側
//這裡忽略了父節點不存在的情況,最後會巧妙的處理這種情況 if(node.parent.left == node){ node.parent.left = null; } else { node.parent.right = null; }
2、存在左結點或者右結點,刪除後需要對子結點移動
刪除結點,需要斷開兩個關係,然後建立父結點和子結點的關係
//先找到子節點,不需要管他是左是右 BSTNode<T> child = null; if(node.left != null){ child = node.left; } else { child = node.right; } //這裡忽略了父節點不存在的情況,最後會巧妙的處理這種情況 //將父節點和子節點建立關係 if(node.parent.left == node){ node.parent.left = child; } else { node.parent.right = child; } child.parent = node.parent;
3、同時存在左右結點,不能簡單刪除,但是可以通過和後繼結點交換後轉為前兩種情況。
當二叉查詢樹以中序遍歷時,遍歷的結果是一個從小到大排列的順序。
當某個結點存在右結點時,後繼結點就是右結點中的最小值,由於左側結點總比右側結點和父結點小,所以後繼結點一定沒有左結點。從這一特點可以看出,後繼結點有可能存在右結點,也有可能沒有任何結點。由於後繼結點最多隻有一個子結點,因此刪除後繼結點時,就變成了3中情況中的前兩種。
轉移結點值的程式碼很容易:
//獲取當前節點的後繼結點 Node<T> successor = successor(node); //轉移值 node.key = successor.key; //後續變成刪除 successor,就變成了前兩種情況 //在圖示例子中,就是第一種沒有子節點的情況 node = successor;
實際上在三種情況中,還有一個特例就是刪除根結點
完整的刪除結點的程式碼
public void delete(T key){ //獲取要刪除的結點 BSTNode<T> node=search(mRoot, key); //如果存在就刪除 if (node!=null) { delete(node); } } private BSTNode<T> delete(BSTNode<T> node) { //第3種情況,如果同時存在左右子結點 if (node.left!=null && node.right!=null) { //獲取後繼結點 BSTNode<T> successor=successor(node); //轉移後繼結點值到當前結點 node.key=successor.key; //把要刪除的當前結點設定為後繼結點 node=successor; } /** * 經過前一步處理,下面只有兩種情況,只能是一個結點或者沒有結點 * 不管是否有子結點,都獲取子結點 */ BSTNode<T> child; if (node.left!=null) { child=node.left; }else{ child=node.right; } /** * 如果child!=null,就說明有一個結點的情況 * 將父結點與子結點關聯上 */ if (child!=null) { child.parent=node.parent; } /** * 如果當前結點沒有父結點(後繼情況到這兒時一定有父結點) * 說明要刪除的就是根結點 */ if (node.parent==null) { /** * 根結點設定為子結點 * 按照前面的邏輯,根只有一個或者沒有結點,所以直接賦child */ mRoot=child; }else if (node==node.parent.left) { /** * 存在父結點,並且當前結點是左結點 * 將父結點的左結點設定為child */ node.parent.left=child; }else { /** * 存在父結點,並且當前結點是右結點 * 將父結點的右結點設定為child */ node.parent.right=child; } //返回被刪除的結點 return node; }
總結刪除結點的思路
1、如果該結點同時存在左右子結點
獲取後繼結點;
轉移後繼結點值到當前結點node;
把要刪除的當前結點設定為後繼結點successor。
2、經過步驟1的處理,下面兩種情況,只能是一個結點或者沒有結點。
不管有沒有結點,都獲取子結點child
if child!=null,就說明有一個結點的情況,此時將父結點與子結點關聯上
if 當前結點沒有父結點(後繼情況到這一定有父結點),說明要刪除的就是根結點,
根結點設定為child
else if 當前結點是父結點的左結點
則將父結點的左結點設定為child
else 當前結點是父結點的右結點
則將父結點的右結點設定為child
3、返回被刪除的結點node