AVL树性质
左右子树高度之差的绝对值不超过1,如果超过2了,就不平衡了。
平衡因子
左右子树高度之差。
比如下图,其中蓝色的为结点的平衡因子。
插入结点时平衡调整步骤
1.找平横因子大于2的结点。
2.找插入新结点后,失去平衡等的最小子树。
3.平横调整。
//因为新加入了一个节点,所以回溯的时候给这个节点高度 +1
node->height = max(get_height(node->left), get_height(node->right)) + 1;
int balance = get_balance(node);//左减右
// 左左失衡
/*即 "失衡结点" 的左子树比右子树高 2,左孩子(即 x)下的左子树比右子树高 1*/
if (balance >= 2 && get_balance(node->left) >= 1)
return ll_ratate(node);
// 左右失衡
/*"失衡结点" 的左子树比右子树高 2,左孩子(即 x)下的右子树比左子树高 1。。*/
if (balance >= 2 && get_balance(node->left) < 0)
return lr_ratate(node);
//右右失衡
/*"失衡结点" 的右子树比左子树高 2,右孩子(即 x)下的右子树比左子树高 1。*/
if (balance <= -2 && get_balance(node->right) < 0)
return rr_ratate(node);
// 右左失衡
/*""失衡结点" 的右子树比左子树高 2,右孩子(即 x)下的左子树比右子树高 1。*/
if (balance <= -2 && get_balance(node->right) > 0)
return rl_ratate(node);
平横调整类型
1.LL型(中为支,高右转)
Node *AVL::ll_ratate(Node *y)
{
Node *x = y->left;
y->left = x->right;
x->right = y;
y->height = max(get_height(y->left), get_height(y->right)) + 1;
x->height = max(get_height(x->left), get_height(x->right)) + 1;//因为加上了自己,所以高度要加一了
return x;
}
2.RR型(中为支,高左转)
Node *AVL::rr_ratate(Node *y)
{
Node *x = y->right;
y->right = x->left;
x->left = y;
y->height = max(get_height(y->left), get_height(y->right)) + 1;
x->height = max(get_height(x->left), get_height(x->right)) + 1;
return x;
}
3.LR型(下二整体先左转,后与LL同)
Node *AVL::lr_ratate(Node *y)
{
Node *x = y->left;
y->left = rr_ratate(x);
return ll_ratate(y);
}
4.RL型(下二整体先右转,后与RR同)
Node *AVL::rl_ratate(Node *y)
{
Node *x = y->right;
y->right = ll_ratate(x);
return rr_ratate(y);
}
删除结点
1.如果结点不是同时拥有左孩子和右孩子。
else{//不是同时拥有左孩子和右孩子,用孩子结点代替被删结点
Node *t = node;//结点t为需要删除的结点
node = node->left ? node->left : node->right;
delete t;
if (node == nullptr) return nullptr;
}//inner else
2.如果结点有左右孩子结点。
a)找左子树的最右结点,删。
b)找右子树的最左结点,删。
if (node->left && node->right){// 找后继结点,但要删掉的结点有左右孩子
Node *x = node->right;
while (x->left) x = x->left;
node->key = x->key;// 后继直接复制,后结点代替被删的结点
node->right = erase_real(x->key, node->right); // 转化为删除后继
}//if
完整代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
class Node
{
public:
int key = 0;
int height = 0;
Node* left = nullptr;
Node* right = nullptr;
Node(int key_t = 0){
key = key_t;
height = 1;
left = right = nullptr;
}
};
class AVL
{
private:
Node* header;//header结点并非根结点,header->left指向的才是根结点。
Node* ll_ratate(Node *y);
Node* rr_ratate(Node *y);
Node* lr_ratate(Node *y);
Node* rl_ratate(Node *y);
int get_height(Node *node);
int get_balance(Node *node);
Node *insert_real(int key, Node *node);
Node *&find_real(int key, Node *&node);
Node *erase_real(int key, Node *node);
void in_order(Node *root);//中序遍历
void root_order(Node *root); // 先序遍历
void after_order(Node *root); //后序遍历
int destory(Node *node);
public:
AVL();
~AVL();
void insert(int key);
Node *find(int key);// (递归实现)查找"AVL"中键值为key的节点
Node *loop_find(int kry);//(非递归实现)查找"AVL"中键值为key的节点
void erase(int key);
void print(int tag);
};
AVL::AVL()
{
header = new Node(-100);
}
AVL::~AVL()
{
destory(header->left); //将多余的那个节点也删除掉
}
int AVL::destory(Node *p)
{
if (p == nullptr) return 0;
destory(p->left);//注意先后次序,如果先把p销毁,那么就会找不到p->left,p->right
destory(p->right);
delete p;
p = nullptr;
}
void AVL::insert(int key)
{
header->left = insert_real(key, header->left);
}
int AVL::get_height(Node *node)
{
if (node == nullptr) return 0;
return node->height;
}
int AVL::get_balance(Node *node)//BF
{
if (node == nullptr) return 0;
return get_height(node->left) - get_height(node->right);
}
Node *AVL::insert_real(int key, Node *node)//返回新的根节点,用来更新根节点
{
if (node == nullptr) return new Node(key);
if (key < node->key) node->left = insert_real(key, node->left); //小于放左边
else if (key > node->key) node->right = insert_real(key, node->right);//大于放右边
else return node;
//因为新加入了一个节点,所以回溯的时候给这个节点高度 +1
node->height = max(get_height(node->left), get_height(node->right)) + 1;
int balance = get_balance(node);//左减右
// 左左失衡
/*即 "失衡结点" 的左子树比右子树高 2,左孩子(即 x)下的左子树比右子树高 1*/
if (balance >= 2 && get_balance(node->left) >= 1)
return ll_ratate(node);
// 左右失衡
/*"失衡结点" 的左子树比右子树高 2,左孩子(即 x)下的右子树比左子树高 1。。*/
if (balance >= 2 && get_balance(node->left) < 0)
return lr_ratate(node);
//右右失衡
/*"失衡结点" 的右子树比左子树高 2,右孩子(即 x)下的右子树比左子树高 1。*/
if (balance <= -2 && get_balance(node->right) < 0)
return rr_ratate(node);
// 右左失衡
/*""失衡结点" 的右子树比左子树高 2,右孩子(即 x)下的左子树比右子树高 1。*/
if (balance <= -2 && get_balance(node->right) > 0)
return rl_ratate(node);
return node;
}
void AVL::print(int tag)
{
if (tag == 1)
{
cout << " 先序遍历 : " << endl;
root_order(header->left);
cout << endl;
}
if (tag == 2)
{
cout << " 中序遍历 : " << endl;
in_order(header->left);
cout << endl;
}
if (tag == 3)
{
cout << " 后序遍历 : " << endl;
after_order(header->left);
cout << endl;
}
}
void AVL::after_order(Node *root)
{
if (root != nullptr){
after_order(root->left);
after_order(root->right);
cout << "[ " << root->key << " , " << root->height << " ]" << endl;
}
}
void AVL::in_order(Node *root)
{
if (root != nullptr){
in_order(root->left);//先打印左子树
cout << "[ " << root->key << " ," << root->height << " ]" << endl;
in_order(root->right);
}
}
void AVL::root_order(Node* root)
{
if (root != nullptr){
cout << "[ " << root->key << " ," << root->height << " ]" << endl;
root_order(root->left);//先打印左子树
root_order(root->right);
}
}
Node *AVL::ll_ratate(Node *y)
{
Node *x = y->left;
y->left = x->right;
x->right = y;
y->height = max(get_height(y->left), get_height(y->right)) + 1;
x->height = max(get_height(x->left), get_height(x->right)) + 1;//因为加上了自己,所以高度要加一了
return x;
}
Node *AVL::rr_ratate(Node *y)
{
Node *x = y->right;
y->right = x->left;
x->left = y;
y->height = max(get_height(y->left), get_height(y->right)) + 1;
x->height = max(get_height(x->left), get_height(x->right)) + 1;
return x;
}
Node *AVL::lr_ratate(Node *y)
{
Node *x = y->left;
y->left = rr_ratate(x);
return ll_ratate(y);
}
Node *AVL::rl_ratate(Node *y)
{
Node *x = y->right;
y->right = ll_ratate(x);
return rr_ratate(y);
}
Node *AVL::find(int key)
{
return find_real(key, header->left);
}
Node *&AVL::find_real(int key, Node *&node)
{
if (node == nullptr) return node;
if (key < node->key) find_real(key, node->left);
else if (key>node->key) find_real(key, node->right);
else return node;
}
Node *AVL::loop_find(int key)
{
Node *p = header->left;// p 指向根节点
while (p && p->key != key){//当指针p非零且还没找到时,继续执行
if (key < p->key) p = p->left;
else p = p->right;
}
return p;
}
void AVL::erase(int key)
{
header->left = erase_real(key, header->left);
}
Node *AVL::erase_real(int key, Node *node)
{
if (node == nullptr){
cout << key << "不在该 AVL 树中" << endl;
return node;
}
if (key < node->key) node->left = erase_real(key, node->left);
else if (key > node->key) node->right = erase_real(key, node->right);
else{
if (node->left && node->right){// 找后继结点,但要删掉的结点有左右孩子
Node *x = node->right;
while (x->left) x = x->left;
node->key = x->key;// 后继直接复制,后结点代替被删的结点
node->right = erase_real(x->key, node->right); // 转化为删除后继
}//if
else{//不是同时拥有左孩子和右孩子,用孩子结点代替被删结点
Node *t = node;//结点t为需要删除的结点
node = node->left ? node->left : node->right;
delete t;
if (node == nullptr) return nullptr;
}//inner else
}//entern else
node->height = max(get_height(node->left), get_height(node->right)) + 1;
int balance = get_balance(node);
if (balance >= 2 && get_balance(node->left) >= 0)// 左左失衡
return ll_ratate(node);
if (balance >= 2 && get_balance(node->left) < 0) // 左右失衡
return lr_ratate(node);
if (balance <= -2 && get_balance(node->right) <= 0)//右右失衡
return rr_ratate(node);
if (balance <= -2 && get_balance(node->right) > 0)// 右左失衡
return rl_ratate(node);
return node;
}
int main()
{
AVL avl;
// test "insert"
vector<int> intVec{ 3, 2, 1, 4, 4, 5, 6, 7, 10, 9, 7, 8 };
for (auto i : intVec)
avl.insert(i);
avl.print(1);
//test "find"
Node *p = nullptr;
cout << ((p = avl.find(2)) ? p->key : -1) << endl; // 2
cout << ((p = avl.find(100)) ? p->key : -1) << endl; // -1
cout << ((p = avl.loop_find(14)) ? p->key : -1) << endl; // 测试找不到 -1
cout << ((p = avl.loop_find(5)) ? p->key : -1) << endl; // 测试找到 5
// test "erase"
avl.erase(100);
avl.print(2);
avl.erase(9);
avl.print(3);
avl.erase(8);
avl.print(3);
return 0;
}
不想手写平衡树的话,可以用pbds库。