樹定義
public class BinarySearchTree<T extends Comparable<? super T>> {
// 二叉樹節點
private static class BinaryNode<T> {
T data;
BinaryNode<T> left, right;
public BinaryNode(T data, BinaryNode<T> left, BinaryNode<T> right) {
this.data = data;
this.left = left;
this.right = right;
}
}
// 樹根
private BinaryNode<T> root;
...
}
搜索節點
// 用於表示搜索結果(作爲內部類)
private static class SearchResult<T> {
BinaryNode<T> target; // 目標節點
BinaryNode<T> parent; // 目標節點之父
// getter & setter ...
}
// 查找關鍵碼 e:返回目標節點及其父節點(插入、刪除時有用)
public SearchResult<T> search(T e) {
SearchResult<T> result = new SearchResult<>();
BinaryNode<T> current = root, parent = null;
while (current != null) {
int compareResult = e.compareTo(current.data);
// 找到了
if (compareResult == 0) {
break;
}
// 記錄父節點,然後:比當前節點小->往左;否則->往右
parent = current;
current = compareResult < 0 ? current.left : current.right;
}
result.target = current;
result.parent = parent;
return result;
}
插入節點
public void insert(T e) {
// 先確定目標節點是否存在
SearchResult<T> result = search(e);
// 已存在
if (result.target != null) {
return;
}
// 插入節點
BinaryNode<T> node = new BinaryNode<>(e, null, null);
// 建立父節點到新插入節點的連接
BinaryNode<T> parent = result.parent;
if (parent == null) { // 爲樹根
root = node;
} else { // 不是樹根
if (e.compareTo(parent.data) < 0) {
parent.left = node;
} else {
parent.right = node;
}
}
}
刪除節點
設待刪除節點爲 v,v 之父爲 p,則根據 v 擁有的非空孩子數,可分爲兩種情況:
(1) v 擁有一個非空孩子
設該非空孩子爲 c,則讓 c 接替 v,成爲 p 的孩子。
(2)v 擁有兩個非空孩子
設 rc 爲 v 的右孩子,在以 rc 爲根的子樹中,找到關鍵碼最小的節點,設爲 t 。
然後將 v 的關鍵碼設爲 t 的關鍵碼(即存放的數據)。因爲 t 的關鍵碼是子樹 rc 中最小的關鍵碼,所以,更新之後,節點 v 的關鍵碼依然小於等於子樹 rc 中的任一節點的關鍵碼,大於左子樹中任一節點的關鍵碼,即符合搜索樹的限定條件。
最後,刪除節點 t 。此時,可以確保節點 t 絕對沒有非空左孩子。(如果有的話,則其左孩子的關鍵碼比 t 的還要小,即 t 就不是關鍵碼最小的節點)
即,情況(2)轉換爲了情況(1)。
// 找到 root 子樹中關鍵碼最小的節點及其父節點
private SearchResult<T> findMinimum(BinaryNode<T> root) {
SearchResult<T> result = new SearchResult<>();
BinaryNode<T> parent = null;
// 一直往左即可找到最小者
if (root != null) {
while (root.left != null) {
parent = root;
root = root.left;
}
}
result.target = root;
result.parent = parent;
return result;
}
// 刪除
public void remove(T e) {
// 先確認目標節點是否存在
SearchResult<T> result = search(e);
// 不存在
if (result.target == null) {
return;
}
BinaryNode<T> target = result.target; // 待刪除節點
BinaryNode<T> parent = result.parent; // 待刪除節點之父
// 待刪除節點有左右兩個非空孩子
// 以待刪除節點爲根,找到其右子樹中關鍵碼最小的節點,讓它代替受死
if (target.left != null && target.right != null) {
SearchResult<T> result1 = findMinimum(target.right);
target.data = result1.target.data;
target = result1.target; // 真正被刪除的節點
parent = result1.parent;
}
// 現在,待刪除節點最多隻有一個非空孩子
// 讓該孩子節點繼承父節點的位置
BinaryNode<T> child = target.left != null ? target.left : target.right;
if (parent != null) { // 待刪除節點不是樹根
if (parent.left == target) {
parent.left = child;
} else {
parent.right = child;
}
} else { // 待刪除節點是樹根
root = child;
}
}