概念介紹
- AVL樹可以將高度控制在o(logn)以內
- 平衡因子
- 左孩子樹高 - 右孩子樹高
- AVL就是平衡因子受限的搜索樹,其中各個節點的平衡因子的絕對值不超過1
- 等價二叉搜索樹
- 兩個二叉搜索樹的中序遍歷序列相同,則稱它們等價;這個平衡算法的依據
- 重新平衡的方法
- AVL的insert,remove導致的失衡通過單旋和雙旋的方式實現重新平衡
- 失衡傳播
- AVL樹刪除節點重新平衡之後,祖先可能失衡,這時候需要由下而上的進行重新平衡操作
統一平衡算法rotateAt
不在乎旋轉的過程,而是窮舉了旋轉過後所有的情況;對,就是根據旋轉之後的各個節點的位置關係做出來的
平衡是3個節點(祖g 父p 子v)和四個子樹的關係,而他們組合在一起總是可以實現下面的模型
- zip 順時針旋轉
- zap – zip 雙旋轉
- zap
- zip – zap
代碼實現
// 引入搜索二叉樹
#include <BstTree.h>
// 理想平衡條件 (左右孩子的高度一樣)
#define Balanced(x) (stature((x).rc) == stature((x).lc))
// 平衡因子
#define BalFac(x) (stature((x).lc) - stature((x).rc))
// AVL平衡條件
#define AvlBalanced(x) (BalFac(x) > -2 && BalFac(x) < 2)
// 找到失衡節點g(x)對應的孩子和孩子的孩子
template<typename T> BinNodePosi(T) tallerChild(BinNodePosi(T) x) {
// 取孩子高度最高的那個,一樣高的時候取同側的那個
if (stature(x->lc) > stature(x->rc)){
return x->lc;
}
if (stature(x->lc) < stature(x->rc)) {
return x->rc;
}
// 取同側孩子
return IsLChild(*x) ? x->lc : x->rc;
}
// 定義平衡二叉樹模板類
template <typename T> class AVL:public BST {
public :
BinNodePosi(T) insert(T const & e); // 插入(重寫)
// 刪除(重寫)
bool remove(T const& e);
};
// 二叉平衡樹 插入操作
template <typename T> BinNodePosi(T) AVL<T>::insert(const T &e) {
// e存在的話 沒有插入的必要
BinNodePosi(T) x = serach(e);
if (x) {
return x;
}
// 插入新節點
BinNodePosi(T) new_child = new BinNode<T>(e, _hot);
_size ++;
// 解決因插入數據而導致的失衡的問題
BinNodePosi(T) g = _hot;
for (; g; g= g->parent){
// 節點失衡
if (!AvlBalanced(*g)){
// 失衡節點的孫子節點
BinNodePosi(T) v = tallerChild(tallerChild(g));
FromParentTo(*g) = rotateAt(v);
// 此時子樹高度復原,g祖先的高度也是會復原, 調整結束
break;
} else {
// 即使未失衡但是高度也可能變化
updateHeight(g);
}
}
return new_child;
}
// 刪除算法
template <typename T> bool AVL::remove(const T &e) {
// 如果不存在 則不需要刪除
BinNodePosi(T)& x = search(e);
if (!x) {
return false;
}
// 按照二叉搜索樹的規則刪除
removeAt(x, _hot);
--size;
// 平衡祖先節點
BinNodePosi(T) g = _hot;
for (; g ; g = g->parent) {
// 失衡節點使用3+4平衡算法平衡
if (!AvlBalanced(g)) {
BinNodePosi(T) v = tallerChild(tallerChild(g));
// 執行平衡算法,將新子樹關聯到原父親; 但是g的位置也要更新成子樹根節點
g = FromParentTo(*g) = rotateAt(v);
// 刪除節點會造成祖先節點失衡傳播,所以還是需要進行後續的輪詢
}
// 即使未失衡但是高度也可能變化
updateHeight(g);
}
return true;
}
// 引入二叉樹
#include "BinTree.h"
//定義二叉搜索樹模板類
template<typename T>
class BST : public BinTree {
protected:
// 命中節點的父親
BinNodePosi(T)_hot;
// 按照3+4結構連接3個節點和四顆子樹
BinNodePosi(T)connect34(BinNodePosi(T) a, BinNodePosi(T) b, BinNodePosi(T) c, BinNodePosi(T) T0,
BinNodePosi(T) T1, BinNodePosi(T) T2, BinNodePosi(T) T3);
// 對父親祖父做同意旋轉調整
BinNodePosi(T)rotateAt(BinNodePosi(T)x);
public:
// 基本接口
// 查找
virtual BinNodePosi(T)&search(T const &e);
// 插入
virtual BinNodePosi(T)insert(T const &e);
// 刪除
virtual bool remove(T const &e);
};
// 二叉搜索樹查找
template<typename T>
BinNodePosi(T)& BST::search(T const &e) {
return searchIn(_root, _hot = NULL, e);
}
// 遞歸查找
template <typename T> BinNodePosi(T)& searchIn(BinNodePosi(T)& v, BinNodePosi(T) & hot, T const &e){
// 遞歸基
if (!v || v->data == e) {
return v;
}
// 設置父指針
hot = v;
// 做減法
v = e > v->data ? v->rc : v->lc;
return searchIn(v, hot, e);
}
// 插入操作
template <typename T> BinNodePosi(T) BST<T>::insert(const T &e) {
BinNodePosi(T) x = search(e);
// 如果已經存在 則沒有意義
if (x) {
return x;
}
// 創建新節點
x = new BinNode(e, hot);
// 更新規模
_size++;
// 更新x祖先高度
updateHeightAbove(x);
return x;
}
// 刪除算法
template <typename T> bool BST<T>::remove(const T &e) {
BinNodePosi(T) x = search(e);
// 目標不存在 則刪除失敗
if (!x) {
return false;
}
// 實施刪除
removeAt(x, _hot);
// 更新規模
_size --;
// 更新祖先節點的高度
updateHeightAbove(_hot);
return true;
};
// 實際刪除操作
template <typename T> static BinNodePosi(T) removeAt(BinNodePosi(T) &x, BinNodePosi(T) & hot) {
// 實際被刪除的節點
BinNodePosi(T) w = x;
// 被刪除節點的替換者
BinNodePosi(T) succ = NULL;
// 單分支直接刪除
if (!HasLChild(x)) {
// *x替換成右子樹
x = succ = x->rc;
} else if (!HasRChild(x)) {
// *x替換成其左子樹
x = succ = x->rc;
} else {
// 雙分支 被刪除的是直接後繼節點
w = w->succ();
// 置換x和直接後繼之間的數據
swap(x->data, w->data);
// 直接後繼肯定是沒有左孩子的
FromParentTo(w) = succ = w->rc;
}
// 記錄實際被刪除的孩子的父親
hot = w->parent;
// 關聯hot和替換者
if (succ) {
succ->parent = hot;
}
// 釋放被刪除的節點
release(w->data);
release(w);
return succ;
};
// BST系欸但那旋轉變化統一算法, 返回調整之後局部子樹根節點的位置
template <typename T> BinNodePosi(T) BST<T>::rotateAt(BinNodePosi(T) x) {
// 父親節點
BinNodePosi(T) p = x->parent;
// 祖父節點
BinNodePosi(T) g = p->parent;
if (IsLChild(*p)) { // zip
if (IsLChild(*v)) { // zip--zip
return connect34(v,p,g,v->lc, v->rc, p->rc,g->rc)
} else {
// zip --zap
return connect34(p,v,g, p->lc,v->lc, v->rc, g->rc);
}
} else {
if (IsRChild(*v)) {
return connect34(g, p, v, g->lc, p->lc, v->lc, v->rc);
} else {
return connect34(g,v,p, g->lc, v->lc, v->rc, p->rc);
}
}
};
// 按照3+4的接口連接3個節點和4顆子樹, 返回局部子樹的根節點
template <typename T> BinNodePosi(T) BST<T>::connect34(BinNode<T> *a, BinNode<T> *b, BinNode<T> *c, BinNode<T> *T0,
BinNode<T> *T1, BinNode<T> *T2, BinNode<T> *T3) {
// 設置b,a,c之間關係
b->lc = a;
a->parent = b;
b->rc = c;
c->parent = b;
// 設置a的左右孩子
a->lc = T0;
if (T0) {
T0->parent = a;
}
a->rc = T1;
if (T1) {
T1->parent = a;
}
// 設置c的左右孩子
c->lc = T2;
if (T2) {
T2->parent = c;
}
c->rc = T3;
if (T3) {
T3->parent = c;
}
return b;
}