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