Self-Balancing Binary Search Tree
定義
任意節點子樹的高度差(稱為平衡因子)不超過1。
節點結構體:
template<class T>
struct Node {
T key;
Node<T>* lchild;
Node<T>* rchild;
Node<T>(T k) : key(k), lchild(nullptr), rchild(nullptr) {}
};
平衡二叉樹類:
template<class T>
class AVLTree {
private:
Node<T>* root;
public:
AVLTree() :root(nullptr) {};
Node<T>* getRoot() { return root; }
void printTree();
Node<T>* llRotation(Node<T>*);
Node<T>* lrRotation(Node<T>*);
Node<T>* rrRotation(Node<T>*);
Node<T>* rlRotation(Node<T>*);
void balance(Node<T>*);
void insert(const T&);
bool remove(Node<T>*, Node<T>*, T);
int getDepth(Node<T>*);
int getBalanceFactor(Node<T>*);
Node<T>* findMin(Node<T>*);
Node<T>* findMax(Node<T>*);
void fixUp(); //修復平衡
Node<T>* find(Node<T>* node, T key);
};
操作
二叉平衡樹與二叉排序樹非常相似,以下重點談談樹的自平衡策略。
左旋的動態過程:
右旋的動態過程:
ll型(右旋)
插入或者刪除導致某節點a失衡(平衡因子絕對值大於1),而且a的左子樹b(a->lchild)的左子樹c(b->lchild)比右子樹d(b->rchild)高。對a節點作ll平衡。
template<class T>
Node<T>* AVLTree<T>::llRotation(Node<T>* node) { //插入節點在左子樹左邊,右旋
Node<T>* temp = node->lchild;
node->lchild = temp->rchild;
temp->rchild = node;
return temp;
}
lr型
插入或者刪除導致某節點a失衡(平衡因子絕對值大於1),而且a的左子樹b(a->lchild)的左子樹c(b->lchild)比右子樹d(b->rchild)矮。對b節點作rr平衡,再對a作ll平衡。
template<class T>
Node<T>* AVLTree<T>::lrRotation(Node<T>* node) { //插入節點在左子樹右邊
Node<T>* temp = node->lchild;
node->lchild = rrRotation(temp);
return llRotation(node);
}
rr型
與ll型對稱
rl型
與lr型對稱
平衡策略
自頂向下查找失衡節點,根據平衡因子的情況作平衡處理。總體而言,是將節點從樹高的一側借調到樹低的一側。(如果Node中有parent指針的話可以自底向上,從插入或刪除節點開始尋找失衡節點)
template<class T>
void AVLTree<T>::balance(Node<T>* node) {
int bf = getBalanceFactor(node); //平衡因子
if (bf > 1) { //失衡,左高
if (getBalanceFactor(node->lchild) > 0) //左左高,ll
root = llRotation(node);
else //左右高,lr
root = lrRotation(node);
}
else if (bf < -1) { //失衡,右高
if (getBalanceFactor(node->rchild) > 0) //右左高,rl
root = rlRotation(node);
else
root = rrRotation(node); //右邊高,rr
}
return;
}
源碼
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
template<class T>
struct Node {
T key;
Node<T>* lchild;
Node<T>* rchild;
Node<T>(T k) : key(k), lchild(nullptr), rchild(nullptr) {}
};
template<class T>
class AVLTree {
private:
Node<T>* root;
public:
AVLTree() :root(nullptr) {};
Node<T>* getRoot() { return root; }
void printTree();
Node<T>* llRotation(Node<T>*);
Node<T>* lrRotation(Node<T>*);
Node<T>* rrRotation(Node<T>*);
Node<T>* rlRotation(Node<T>*);
void balance(Node<T>*);
void insert(const T&);
bool remove(Node<T>*, Node<T>*, T);
int getDepth(Node<T>*);
int getBalanceFactor(Node<T>*);
Node<T>* findMin(Node<T>*);
Node<T>* findMax(Node<T>*);
void fixUp();
Node<T>* find(Node<T>* node, T key);
};
template<class T>
void AVLTree<T>::printTree() { //層次遍歷
Node<T>* pos = root; //當前位置
Node<T>* flag = root; //層末標識
queue<Node<T>*> q;
q.push(root); //根節點入隊
while (!q.empty()) { //隊列非空
Node<T>* node = q.front();
q.pop(); //彈出隊首
cout << node->key << '\t';
if (node->lchild != nullptr) { //左孩子非空則入隊
q.push(node->lchild);
pos = node->lchild;
}
if (node->rchild != nullptr) { //右孩子非空則入隊
q.push(node->rchild);
pos = node->rchild;
}
if (node == flag) { //抵達層末
flag = pos;
cout << "\n";
}
}
}
template<class T>
void AVLTree<T>::insert(const T& key) {
Node<T>* node = new Node<T>(key);
if (root == nullptr) {
root = node;
return;
}
Node<T>* pos = root;
while (true) { //查找插入位置
if (node->key < pos->key) {
if (pos->lchild == nullptr) {
pos->lchild = node;
fixUp();
return;
} //end if
else
pos = pos->lchild;
} //end if
else if (node->key > pos->key) {
if (pos->rchild == nullptr) {
pos->rchild = node;
fixUp();
return;
} //end if
else
pos = pos->rchild;
} //end if
else
return; //樹中已有此節點則無操作
} //end while
}
template<class T>
int AVLTree<T>::getDepth(Node<T>* node) {
if (node == nullptr)
return 0;
return max(getDepth(node->lchild), getDepth(node->rchild)) + 1;
}
template<class T>
int AVLTree<T>::getBalanceFactor(Node<T>* node) { //平衡因子 = 左子樹高-右子樹高
return getDepth(node->lchild) - getDepth(node->rchild);
}
template<class T>
void AVLTree<T>::balance(Node<T>* node) {
int bf = getBalanceFactor(node);
if (bf > 1) {
if (getBalanceFactor(node->lchild) > 0)
root = llRotation(node);
else
root = lrRotation(node);
}
else if (bf < -1) {
if (getBalanceFactor(node->rchild) > 0)
root = rlRotation(node);
else
root = rrRotation(node);
}
return;
}
template<class T>
Node<T>* AVLTree<T>::llRotation(Node<T>* node) { //插入節點在左子樹左邊,右旋
Node<T>* temp = node->lchild;
node->lchild = temp->rchild;
temp->rchild = node;
return temp;
}
template<class T>
Node<T>* AVLTree<T>::lrRotation(Node<T>* node) { //插入節點在左子樹右邊
Node<T>* temp = node->lchild;
node->lchild = rrRotation(temp);
return llRotation(node);
}
template<class T>
Node<T>* AVLTree<T>::rlRotation(Node<T>* node) { //插入節點在右子樹左邊
Node<T>* temp = node->rchild;
node->rchild = llRotation(temp);
return rrRotation(node);
}
template<class T>
Node<T>* AVLTree<T>::rrRotation(Node<T>* node) { //插入節點在右子樹左邊,左旋
Node<T>* temp = node->rchild;
node->rchild = temp->lchild;
temp->lchild = node;
return temp;
}
template<class T>
bool AVLTree<T>::remove(Node<T>* node, Node<T>* parent, T key) {
Node<T>* temp = nullptr;
if (node == nullptr) // 未找到目標節點
return false;
else if (key < node->key)
return remove(node->lchild, node, key);
else if (key > node->key)
return remove(node->rchild, node, key);
else if (node->lchild && node->rchild) { //刪除節點有左子樹也有右子樹
if (getDepth(node->lchild) > getDepth(node->rchild)) { //左子樹高,前驅替代
temp = findMax(node->lchild);
node->key = temp->key;
return remove(node->lchild,node, node->key);
}
else { //右子樹不比左子樹矮,后驅替代
temp = findMin(node->rchild);
node->key = temp->key;
return remove(node->rchild, node, node->key);
}
}
else {
if ((node->lchild && node->rchild == nullptr)) { //刪除節點有左孩子無右孩子
temp = findMax(node->lchild);
node->key = temp->key;
return remove(node->lchild, node, node->key);
}
else if (node->rchild && node->lchild == nullptr) { //刪除節點有右孩子無左孩子
temp = findMin(node->rchild);
node->key = temp->key;
return remove(node->rchild, node, node->key);
} //end if
else { //刪除節點最終遞歸到刪除葉子節點
if (node == parent->lchild) //父節點指針置空
parent->lchild = nullptr;
else
parent->rchild = nullptr;
delete node; //釋放子節點
node = nullptr;
fixUp();
}
} //end else
return true;
}
template<class T>
void AVLTree<T>::fixUp() {
Node<T>* temp = this->root; //自頂向下調整樹
while (1) //尋找失衡的節點
{
if (getBalanceFactor(temp) == 2) {
if (fabs(getBalanceFactor(temp->lchild)) == 1)
break;
else
temp = temp->lchild;
}
else if (getBalanceFactor(temp) == -2) {
if (fabs(getBalanceFactor(temp->rchild)) == 1)
break;
else
temp = temp->rchild;
}
else break;
}
balance(temp);
return;
}
template<class T>
Node<T>* AVLTree<T>::find(Node<T>* node, T key) {
while (node != nullptr && key != node->key) { //迭代查找
if (key < node->key)
node = node->lchild;
else
node = node->rchild;
}
if (node == nullptr)
cout << "Element " << key << " doesn't exist!" << endl;
else
cout << "Element " << key << " exists." << endl;
return node;
}
template<class T>
Node<T>* AVLTree<T>::findMax(Node<T>* node) {
if (node != nullptr) {
while (node->rchild)
node = node->rchild;
}
return node;
}
template<class T>
Node<T>* AVLTree<T>::findMin(Node<T>* node) {
if (node != nullptr) {
if (node->lchild == nullptr) //左孩子為空,當前節點已是最左下
return node;
else
return findMin(node->lchild); //左孩子不為空,往左子樹遍歷
}
else
return nullptr; //空樹返回nullptr
}
int main() {
int arr[]{ 7,4,8,5,1,6};//ll:738512建樹;rr:7385129刪除2;rl:7385124刪除4;lr:748516建樹
AVLTree<int> avl;
for (int i = 0; i < 6; i++)
{
avl.insert(arr[i]);
}
avl.printTree();
avl.find(avl.getRoot(),8);
avl.remove(avl.getRoot(), nullptr, 8);
avl.printTree();
}