二叉查找樹定義
二叉查找樹(Binary Search Tree), 也稱為二叉搜索樹, 有序二叉樹(ordered binary tree), 排序二叉樹(sorted binary tree), 是指一顆空樹或具有以下性質的二叉樹:
1. 任意節點的左子樹不空, 則左子樹上所有節點的值均小于它的根節點的值
2. 任意節點的右子樹不空, 則右子樹上所有節點均大于它的根節點的值
3. 任意節點的左,右子樹也分別為二叉查找樹
4. 沒有鍵值相等的節點
二叉查找樹通常采用二叉鏈表作為二叉查找樹的存儲結構, 相比于其他數據結構的優勢在于查找,插入時間復雜度較低, 為O(log n). 它是基礎的數據結構, 用于構建 紅黑數, B-Tree, B+Tree, B*Tree等.
二叉查找樹的Java實現
1. 二叉查找樹節點定義
public class BSTNode<T extends Comparable<T>> {
T key; // 關鍵字(鍵值)
BSTNode<T> left; // 左孩子
BSTNode<T> right; // 右孩子
BSTNode<T> parent; // 父結點
public BSTNode(T key, BSTNode<T> parent, BSTNode<T> left, BSTNode<T> right) {
this.key = key;
this.parent = parent;
this.left = left;
this.right = right;
}
public T getKey() {
return key;
}
public String toString() {
return "key:"+key;
}
}
BSTNode是二叉查找樹的內部節點, 它包含以下信息:
- key 對二叉樹進行排序的依據
- left 左邊子節點
- right 右邊子節點
- parent 當前節點的父節點
2. 二叉查找樹的查找
/*
* (遞歸實現)查找"二叉樹x"中鍵值為key的節點
*/
private BSTNode<T> search(BSTNode<T> x, T key) {
if (x==null)
return x;
int cmp = key.compareTo(x.key);
if (cmp < 0)
return search(x.left, key);
else if (cmp > 0)
return search(x.right, key);
else
return x;
}
public BSTNode<T> search(T key) {
return search(mRoot, key);
}
search 的過程比較簡單, 從根節點開始, 根據給定的key與節點的key值進行比較, 直到 "cmp" = 0 或節點x = 0.
3. 查找最大值, 最小值
最大值
/*
* 查找最大結點:返回tree為根結點的二叉樹的最大結點。
*/
private BSTNode<T> maximum(BSTNode<T> tree) {
if (tree == null)
return null;
while(tree.right != null)
tree = tree.right;
return tree;
}
public T maximum() {
BSTNode<T> p = maximum(mRoot);
if (p != null)
return p.key;
return null;
}
最小值
/*
* 查找最小結點:返回tree為根結點的二叉樹的最小結點。
*/
private BSTNode<T> minimum(BSTNode<T> tree) {
if (tree == null)
return null;
while(tree.left != null)
tree = tree.left;
return tree;
}
public T minimum() {
BSTNode<T> p = minimum(mRoot);
if (p != null)
return p.key;
return null;
}
4. 查找前繼節點(predecessor) 后繼節點(successor)
查找前繼節點
/*
* 找結點(x)的前繼結點。即,查找"二叉樹中數據值小于該結點"的"最大結點"。
*/
public BSTNode<T> predecessor(BSTNode<T> x) {
// 如果x存在左孩子,則"x的前繼結點"為 "以其左孩子為根的子樹的最大結點"。
if (x.left != null)
return maximum(x.left);
// 如果x沒有左孩子。則x由分以下兩種情況討論:
// (01) x是"一個右孩子",則"x的前驅結點"為 "它的父結點"。
// (01) x是"一個左孩子",則查找"x的最低的父結點,并且x在該父結點右子樹上孩子或是其又子節點",找到的這個"最低的父結點"就是"x的前繼結點"。
BSTNode<T> y = x.parent;
while ((y!=null) && (x==y.left)) {
x = y;
y = y.parent;
}
return y;
}
查找后繼節點
/*
* 找結點(x)的后繼結點。即,查找"二叉樹中數據值大于該結點"的"最小結點"。
*/
public BSTNode<T> successor(BSTNode<T> x) {
// 如果x存在右孩子,則"x的后繼結點"為 "以其右孩子為根的子樹的最小結點"。
if (x.right != null)
return minimum(x.right);
// 如果x沒有右孩子。則x分以下兩種情況進行討論:
// (01) x是"一個左孩子",則"x的后繼結點"為 "它的父結點"。
// (02) x是"一個右孩子",則查找"x的最低的父結點,并且x是該父結點左子樹上的孩子節點或直接是左子節點",找到的這個"最低的父結點"就是"x的后繼結點"。
BSTNode<T> y = x.parent;
while ((y!=null) && (x==y.right)) {
x = y;
y = y.parent;
}
return y;
}
5. 插入節點
/*
* 將結點插入到二叉樹中
*
* 參數說明:
* tree 二叉樹的
* z 插入的結點
*/
private void insert(BSTree<T> bst, BSTNode<T> z) {
int cmp;
BSTNode<T> y = null;
BSTNode<T> x = bst.mRoot;
// 1. 查找z的插入位置
while (x != null) {
y = x;
cmp = z.key.compareTo(x.key);
if (cmp < 0)
x = x.left;
else
x = x.right;
}
//2. 根據位置決定放在root節點, y的左/右邊
z.parent = y;
if (y==null) // y是null
bst.mRoot = z;
else {
cmp = z.key.compareTo(y.key);
if (cmp < 0)
y.left = z;
else
y.right = z;
}
}
/*
* 新建結點(key),并將其插入到二叉樹中
*
* 參數說明:
* tree 二叉樹的根結點
* key 插入結點的鍵值
*/
public void insert(T key) {
BSTNode<T> z=new BSTNode<T>(key,null,null,null);
// 如果新建結點失敗,則返回。
if (z != null)
insert(this, z);
}
5. 刪除節點
/*
* 刪除結點(z),并返回被刪除的結點
*
* 參數說明:
* bst 二叉樹
* z 刪除的結點
*/
private BSTNode<T> remove(BSTree<T> bst, BSTNode<T> z) {
BSTNode<T> x=null;
BSTNode<T> y=null;
/** 1. 待刪除節點情況
* 1) 節點z最多一個子節點, 則刪除z后將對應子節點代替原來的位置
* 2) 節點有兩個子節點, 調用 successor方法獲取其后繼節點, 后繼節點代替原來的那個節點
*/
if ((z.left == null) || (z.right == null) )
y = z; // 節點z最多有一個子節點
else{
// 這里有個知識點, 既然y是后繼節點, 則 y 必定沒有兩個子節點
y = successor(z); // 節點z有兩個子節點, 則調用 successor 查詢z對應的子節點
}
// 2. 將待刪除節點的子節點賦值給x
if (y.left != null)
x = y.left;
else
x = y.right;
/**
* x 情況
* 1. x是被刪除節點的子節點
* 2. x是被刪除節點的后繼節點的子節點
*/
if (x != null) {
x.parent = y.parent;
}
// y.parent == null, 則說明y是mRoot節點
if (y.parent == null)
bst.mRoot = x;
else if (y == y.parent.left)
y.parent.left = x;
else
y.parent.right = x;
// 若y是z的后繼節點
if (y != z) {
z.key = y.key;
}
return y;
}
6. 二叉查找樹完整實現代碼
二叉查找樹Java實現 BSTree.java
總結
二叉查找樹總體實現比較簡單, 但這是學習 RBTree, B-Tree, B+Tree 等數據結構的基礎