二叉查詢樹的刪除過程
阿新 • • 發佈:2018-12-22
定義:
一顆二叉查詢樹是一顆二叉樹,其中每個結點都包含一個Comparable的鍵(以及向關聯的值)且每個結點的鍵都大於其左子樹中的任意結點的鍵而小於右子樹中任意結點的鍵
插入實現:
先遞迴找出新結點插入的位置;邏輯是如果樹是空的,就返回一個含有該鍵值對的新節點,如果要插入的鍵小於根結點的鍵,就繼續在左子樹遞迴查詢插入改鍵,否則在右子樹中插入該鍵
private Node put(Node x,Key key,Value value) { if(x==null) return new Node(key,value); int cmp = key.compareTo(x.key); //找出要插入的結點在二叉樹中的位置 if(cmp < 0) x.left = put(x.left,key,value); else if(cmp > 0) x.right = put(x.right,key,value); return x; }
刪除:
二叉查詢樹用遞迴方法實現的話,我們在方法引數裡面接受一個指向結點的連結,然後返回一個指向結點的連結。
第一個方法 deleteMin():刪除一棵樹中的最小結點,輸入樹的根結點,返回刪除之後的替換結點
private Node deleteMin(Node x) {
if(x.left==null)
return x;
x.left = deleteMin(x.left);
return x;
}
不斷遍歷根結點的左子樹直到遇見一個空連結,然後將指向該結點(即找到的左子樹為空的結點)的連結指向該結點的右子樹;此時已經沒有任何連結指向要被刪除的結點,因此它就會被垃圾收集器清理掉
第二個方法 delete(Node x,Key key):
如果要刪除的結點只有一個子樹,我們可以直接用上面的方法類似的原理直接刪除;但是如果要刪除的結點有兩個子樹就要考慮刪除之後保證二叉樹的平衡;主要方法就是用待刪除結點x的後繼節點來替換x的位置;因為x右子樹不為空,因此它的後繼節點就是其右子樹中的最小節點。
主要分四個步驟:
- 將指向被刪除結點的連結儲存為t
- 設定被刪除結點的後繼結點min(.right)為x設定被刪除結點的後繼結點min(.right)為x
- 將x的右連結(原本指向一顆所有結點都大於x.key的二叉查詢樹)指向dele-teMin(t.right),也就是用deleteMin(t.right)來作為替換結點的右子樹
- 再讓x的左連結指向被刪除結點的左子樹(t.left),因為主要操作在右子樹,左子樹無需變化
private Node delete(Node x,Key key) { //Node為根節點,Key即為要刪除的節點的值
if(x==null)
return null;
int cmp = key.compareTo(x.key);
if(cmp < 0) //找到要刪除的節點的位置
x.left = delete(x.left,key);
else if(cmp > 0)
x.right = delete(x.right,key);
else
{
//判斷刪除節點是否有兩個孩子
if(x.right == null) //如果只有一個孩子,則直接返回另一個孩子的連結,即用x的孩子直接替換x節點
return x.left;
if(x.left == null)
return x.right;
Node t = x; //將x賦給t
x = min(t.right); //用x的後繼節點替換x
//用被刪除節點刪除後繼節點(後繼節點原本存在於被刪除節點的右子樹中)之後的右子樹來作為替換節點的右子樹
x.right = deleteMin(t.right);
x.left = t.left; //把被刪除節點的左子樹作為替換節點的左子樹
}
return x;
}
完整程式碼
public class BST <Key extends Comparable<Key>,Value>{
private Node root;
private class Node{
private Key key;
private Value value;
private Node left,right;
public Node(Key key,Value value){
this.key =key;
this.value = value;
}
}
public void put(Key key,Value value) {
root = put(root,key,value);
}
public void delete(Key key) {
root = delete(root,key);
}
//查詢數中最小節點
private Node min(Node x) {
if(x.left == null) //一直遞迴遍歷二叉查詢數的左子樹,直到為null
return x;
return min(x.left);
}
private Node deleteMin(Node x) {
if(x.left==null)
return x;
x.left = deleteMin(x.left);
return x;
}
private Node put(Node x,Key key,Value value) {
if(x==null)
return new Node(key,value);
int cmp = key.compareTo(x.key); //找出要插入的結點在二叉樹中的位置
if(cmp < 0)
x.left = put(x.left,key,value);
else if(cmp > 0)
x.right = put(x.right,key,value);
return x;
}
private Node delete(Node x,Key key) { //Node為根節點,Key即為要刪除的節點的值
if(x==null)
return null;
int cmp = key.compareTo(x.key);
if(cmp < 0) //找到要刪除的節點的位置
x.left = delete(x.left,key);
else if(cmp > 0)
x.right = delete(x.right,key);
else
{
//判斷刪除節點是否有兩個孩子
if(x.right == null) //如果只有一個孩子,則直接返回另一個孩子的連結,即用x的孩子直接替換x節點
return x.left;
if(x.left == null)
return x.right;
Node t = x; //將x賦給t
x = min(t.right); //用x的後繼節點替換x
//用被刪除節點刪除後繼節點(後繼節點原本存在於被刪除節點的右子樹中)之後的右子樹來作為替換節點的右子樹
x.right = deleteMin(t.right);
x.left = t.left; //把被刪除節點的左子樹作為替換節點的左子樹
}
return x;
}
}
輸出方方法可以自己選擇遍歷方式實現,和二叉樹一樣