目录
1.AVL树的概念
二叉搜索树可以缩短查找的效率,但在某些情况二叉搜索树会发生退化变成单支树,这是查找的效率对下。
AVL树是在二叉搜索树原有的规则下,加以限制:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
一颗具有以下性质的二叉搜索树,是AVL树:
1. 每个节点的左右子树的高度之差(平衡因子)的绝对值不超过-1、0、1
2. 每个节点的左右子树都是AVL树
3. 空树也是AVL树
平衡因子 = 右子树高度 - 左子树高度(也可以是左-右,不影响)
一颗n个节点的AVL树,其高度可保持在左右,搜索时间复杂度为O(log n)
2.AVL树的操作(KV模型)
2.1 AVL树的节点定义
AVL树的节点可以使用三叉链结构,_parent指向节点的父节点
template <class K, class V>
struct AVLTreeNode
{
AVLTreeNode(const pair<K, V>& kv)
:_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr),_bf(0)
{}
//三叉链
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
pair<K, V> _kv;
//平衡因子:右 - 左,平衡因子的绝对值 ≤ 1
int _bf;
};
2.2 AVL树的查找
查找的key小于当前节点的key,则向左继续查找
查找的key大于当前节点的key,则向右继续查找
走到nullptr,说明查找的key值不存在
Node* find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (key > cur->_kv.first)
cur = cur->_right;
else if (key < cur->_kv.first)
cur = cur->_left;
else
return cur;
}
//key不存在
return nullptr;
}
2.3 AVL树的插入
AVL树的插入过程:
1. 先查找key值的位置,若key值已存在就结束查找;若key值不存在就找到插入位置并插入。
2. 调整平衡因子:
插入一个节点,会影响部分祖先节点的平衡因子
插入在左子树,平衡因子--
插入在右子树,平衡因子++
是否继续往上更新祖先的平衡因子,需要看parent的子树的高度是否变化:
3. 平衡因子等于2/-2时,需要进行旋转操作,调整数的结构使之平衡:
a. 新节点插入较高左子树的左侧--右单旋
旋转之后根节点的平衡因子变为0,不再需要向上更新平衡因子
连接根节点的parent指针时,需要判断根节点是上层节点的左孩子还是右孩子
//右旋
void RotateR(Node* parent)
{
Node* parent_L = parent->_left;
Node* parent_L_R = parent_L->_right;
parent->_left = parent_L_R;
if(parent_L_R != nullptr)
parent_L_R->_parent = parent;
Node* parent_parent = parent->_parent;
parent_L->_right = parent;
parent->_parent = parent_L;
//parent_L更新后是根节点
if (parent_parent == nullptr)
{
_root = parent_L;
parent_L->_parent = nullptr;
}
//parent_L 更新后不是根节点,可能属于上层节点的左节点或右节点
else
{
if (parent == parent_parent->_left)
{
parent_L->_parent = parent_parent;
parent_parent->_left = parent_L;
}
else
{
parent_L->_parent = parent_parent;
parent_parent->_right = parent_L;
}
}
//更新_bf
parent->_bf = parent_L->_bf = 0;
}
b. 新节点插入较高右子树的右侧--左单旋
旋转之后根节点的平衡因子变为0,不再需要向上更新平衡因子
连接根节点的parent指针时,需要判断根节点是上层节点的左孩子还是右孩子
//左旋
void RotateL(Node* parent)
{
Node* parent_R = parent->_right;
Node* parent_R_L = parent_R->_left;
parent->_right = parent_R_L;
if (parent_R_L != nullptr)
parent_R_L->_parent = parent;
Node* parent_parent = parent->_parent;
parent_R->_left = parent;
parent->_parent = parent_R;
//parent_R更新后是根节点
if (parent_parent == nullptr)
{
_root = parent_R;
parent_R->_parent = nullptr;
}
//parent_R 更新后不是根节点,可能属于上层节点的左节点或右节点
else
{
if (parent == parent_parent->_left)
{
parent_R->_parent = parent_parent;
parent_parent->_left = parent_R;
}
else
{
parent_R->_parent = parent_parent;
parent_parent->_right = parent_R;
}
}
parent->_bf = parent_R->_bf = 0;
}
c. 新节点插入较高左子树的右侧--左单旋(左子树)+右单旋(整体)
两次旋转后根节点的平衡因子为0
根节点左右子树的平衡因子由插入位置是b和c有关,插入b则根节点右子树平衡因子为1,左子树平衡因子为0;插入c则根节点左子树平衡因子为-1,右子树平衡因子为0。
//左旋+右旋
void RotateLR(Node* parent)
{
Node* parent_L = parent->_left;
Node* parent_L_R = parent_L->_right;
int bf = parent_L_R->_bf;
RotateL(parent_L);
RotateR(parent);
//更新_bf
if (bf == 0)
{
parent->_bf = 0;
parent_L->_bf = 0;
parent_L_R->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
parent_L->_bf = 0;
parent_L_R->_bf = 0;
}
else if (bf == 1)
{
parent_L->_bf = -1;
parent->_bf = 0;
parent_L_R->_bf = 0;
}
else//意外处理
{
//cout << "bf超过2" << endl;
assert(false);
}
}
d. 新节点插入较高右子树的左侧--右单旋(右子树)+ 左单旋(整体)
两次旋转后根节点的平衡因子为0
根节点左右子树的平衡因子由插入位置是b和c有关,插入b则根节点左子树平衡因子为0,右子树平衡因子为1;插入c则根节点右子树平衡因子为0,左子树平衡因子为-1。
//右旋+左旋
void RotateRL(Node* parent)
{
Node* parent_R = parent->_right;
Node* parent_R_L = parent_R->_left;
int bf = parent_R_L->_bf;
RotateR(parent_R);
RotateL(parent);
//更新_bf
if (bf == 0)
{
parent->_bf = 0;
parent_R->_bf = 0;
parent_R_L->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
parent_R->_bf = 0;
parent_R_L->_bf = 0;
}
else if (bf == -1)
{
parent_R->_bf = 1;
parent->_bf = 0;
parent_R_L->_bf = 0;
}
else//意外处理
{
cout << "bf超出2" << endl;
assert(false);
}
}
insert的整体代码:
bool insert(const pair<K, V>& kv)
{
//插入一个节点,会影响部分祖先节点的平衡因子
//插入在左子树,平衡因子--
//插入在右子树,平衡因子++
//是否继续往上更新祖先的平衡因子,需要看parent的子树的高度是否变化:
//1. parent的平衡因子 == 0
//说明parent的平衡因子更新前是1/-1,插入节点插入矮的一边,parent所在子树高度不变,不需要继续往上更新
//2. parent的平衡因子 == 1/-1
// 说明parent的平衡因子更新前是0,插入节点插入任意一边,parent所在子树高度都会变化,需要继续向上更新
//3. parent的平衡因子 == 2/-2
//说明parent的平衡因子更新前是1/-1,插入节点插入在高的那边,进一步加剧parent所在的子树的平衡,违反AVL规则,需要旋转处理
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
//查找
while (cur)
{
if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (kv.second < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else
//key重复
return false;
}
//插入
cur = new Node(kv);
if (kv.first > parent->_kv.first)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//更新平衡因子_bf
while (parent)
{
//更新_bf
if (cur == parent->_left)
parent->_bf--;
else
parent->_bf++;
//没有增高,就不需要向上更新了
if (parent->_bf == 0)
break;
//增高了,需要继续向上更新_bf
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
parent = parent->_parent;
}
//增高了,_bf == 2,AVL树不平衡了,需要旋转了
else if (parent->_bf == 2 || parent->_bf == -2)
{
//四种情况
//右旋
if (parent->_bf == -2 && cur->_bf == -1)
RotateR(parent);
//左旋
else if (parent->_bf == 2 && cur->_bf == 1)
RotateL(parent);
//左旋+右旋
else if (parent->_bf == -2 && cur->_bf == 1)
RotateLR(parent);
//右旋+左旋
else if (parent->_bf == 2 && cur->_bf == -1)
RotateRL(parent);
//旋转后该子树的根的_bf == 0,不需要再向上更新_bf了
break;
}
else//意外处理
{
//cout << "平衡因子的绝对值超过2" << endl;
assert(false);
}
}
return true;
}
//左旋
void RotateL(Node* parent)
{
Node* parent_R = parent->_right;
Node* parent_R_L = parent_R->_left;
parent->_right = parent_R_L;
if (parent_R_L != nullptr)
parent_R_L->_parent = parent;
Node* parent_parent = parent->_parent;
parent_R->_left = parent;
parent->_parent = parent_R;
//parent_R更新后是根节点
if (parent_parent == nullptr)
{
_root = parent_R;
parent_R->_parent = nullptr;
}
//parent_R 更新后不是根节点,可能属于上层节点的左节点或右节点
else
{
if (parent == parent_parent->_left)
{
parent_R->_parent = parent_parent;
parent_parent->_left = parent_R;
}
else
{
parent_R->_parent = parent_parent;
parent_parent->_right = parent_R;
}
}
parent->_bf = parent_R->_bf = 0;
}
//右旋
void RotateR(Node* parent)
{
Node* parent_L = parent->_left;
Node* parent_L_R = parent_L->_right;
parent->_left = parent_L_R;
if(parent_L_R != nullptr)
parent_L_R->_parent = parent;
Node* parent_parent = parent->_parent;
parent_L->_right = parent;
parent->_parent = parent_L;
//parent_L更新后是根节点
if (parent_parent == nullptr)
{
_root = parent_L;
parent_L->_parent = nullptr;
}
//parent_L 更新后不是根节点,可能属于上层节点的左节点或右节点
else
{
if (parent == parent_parent->_left)
{
parent_L->_parent = parent_parent;
parent_parent->_left = parent_L;
}
else
{
parent_L->_parent = parent_parent;
parent_parent->_right = parent_L;
}
}
//更新_bf
parent->_bf = parent_L->_bf = 0;
}
//右旋+左旋
void RotateRL(Node* parent)
{
Node* parent_R = parent->_right;
Node* parent_R_L = parent_R->_left;
int bf = parent_R_L->_bf;
RotateR(parent_R);
RotateL(parent);
//更新_bf
if (bf == 0)
{
parent->_bf = 0;
parent_R->_bf = 0;
parent_R_L->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
parent_R->_bf = 0;
parent_R_L->_bf = 0;
}
else if (bf == -1)
{
parent_R->_bf = 1;
parent->_bf = 0;
parent_R_L->_bf = 0;
}
else//意外处理
{
cout << "bf超出2" << endl;
assert(false);
}
}
//左旋+右旋
void RotateLR(Node* parent)
{
Node* parent_L = parent->_left;
Node* parent_L_R = parent_L->_right;
int bf = parent_L_R->_bf;
RotateL(parent_L);
RotateR(parent);
//更新_bf
if (bf == 0)
{
parent->_bf = 0;
parent_L->_bf = 0;
parent_L_R->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
parent_L->_bf = 0;
parent_L_R->_bf = 0;
}
else if (bf == 1)
{
parent_L->_bf = -1;
parent->_bf = 0;
parent_L_R->_bf = 0;
}
else//意外处理
{
//cout << "bf超过2" << endl;
assert(false);
}
}
2.4 AVL树的删除
在二叉搜索树的篇章介绍了二叉搜索树的删除,分为四种情况,这一步AVL树的删除与二叉搜索树的操作相同,只不过AVL树删除节点后需要更新平衡因子,最差情况需要一直调整到根节点的位置。
AVL树删除操作过程:
1. 根据key值找到需要删除的节点(走到nullptr说明该节点不存在)
2. 删除节点:
a. 删除节点没有孩子节点,直接删除
b. 删除节点只有一个孩子节点,孩子节点替代删除节点的位置,删除节点
c. 删除节点有两个孩子节点,向删除节点的右子树查找key值最小节点,将最小节点的key值覆盖删除节点的key,接着删除最小节点(此时最小节点一定没有孩子节点或只有一个右孩子节点,删除该节点属于a或b情况;最小节点是最左的节点)
3. 调整平衡因子:
删除一个节点,会影响部分祖先节点的平衡因子
删除在左子树,平衡因子++
删除在右子树,平衡因子--
是否继续往上更新祖先的平衡因子,需要看parent的子树的高度是否变化:
旋转处理:
1. 删除节点在较低左子树:
2. 删除节点在较低右子树:
bool erase(const K& key)
{
if (_root == nullptr)
return false;
//查找
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (key > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else //key == cur->_kv.first
break;
}
//判断cur是否为空,空表示不存在
if (cur == nullptr)
return false;
//key找到了,进行删除,删除有4种情况
//
//删除节点没有孩子节点
//删除节点只有一个右孩子节点
if (cur->_left == nullptr)
{
//cur是根节点
if (parent == nullptr)
{
_root = cur->_right;
if(_root != nullptr)
_root->_parent = nullptr;
//bf不变
delete cur;
return true;
}
//不是根节点
else
{
//删除节点是parent的左边
if (cur == parent->_left)
{
parent->_left = cur->_right;
if (cur->_right != nullptr)
cur->_right->_parent = parent;
parent->_bf++;
}
//删除节点是parent的右边
else if (cur == parent->_right)
{
parent->_right = cur->_right;
if (cur->_right != nullptr)
cur->_right->_parent = parent;
parent->_bf--;
}
}
}
//删除节点只有一个左孩子
else if (cur->_right == nullptr)
{
//cur是根节点
if (parent == nullptr)
{
_root = cur->_left;
if(_root != nullptr)
_root->_parent = nullptr;
//bf不变
delete cur;
return true;
}
//cur不是根节点
else
{
//删除节点是parent的左节点
if (cur == parent->_left)
{
parent->_left = cur->_left;
if (cur->_left != nullptr)
cur->_left->_parent = parent;
parent->_bf++;
}
else if (cur == parent->_right)
{
parent->_right = cur->_left;
if (cur->_left != nullptr)
cur->_left->_parent = parent;
parent->_bf--;
}
}
}
//删除节点有两个孩子节点
else
{
Node* minNode = cur->_right;
Node* minNodeParent = cur;
while (minNode->_left != nullptr)
{
//最左就是最小节点
minNodeParent = minNode;
minNode = minNode->_left;
}
//覆盖cur的kv
cur->_kv = minNode->_kv;
//删除最小节点
if (minNode == minNodeParent->_left)
{
minNodeParent->_left = minNode->_right;
if (minNode->_right != nullptr)
minNode->_right->_parent = minNodeParent;
minNodeParent->_bf++;
cur = minNode;
parent = minNodeParent;
}
else//注意这个情况--cur就是minNodeParent
{
minNodeParent->_right = minNode->_right;
if (minNode->_right != nullptr)
minNode->_right->_parent = minNodeParent;
minNodeParent->_bf--;
cur = minNode;
parent = minNodeParent;
}
}
Node* needDelete = cur;
//更新平衡因子_bf
//删除一个节点,parent所在子树不一定全部都矮一节
//第一次不需要改变parent的bf,因为上面删除操作时就改变了parent的bf,第一次只需要判断是否需要向上改变bf或旋转操作
bool flag_first = false;
while (parent)
{
if(flag_first)
{
//更新_bf
if (cur == parent->_left)
//减去-1等于+1
parent->_bf++;
else
parent->_bf--;
}
flag_first = true;
//删除后为1/-1,整体最高高度不变,不需要继续向上更新
if (parent->_bf == 1 || parent->_bf == -1)
break;
//删除后为0,说明整体高度变矮了
else if (parent->_bf == 0)
{
cur = parent;
parent = parent->_parent;
}
//_bf == 2,AVL树不平衡了,需要旋转了
else if (parent->_bf == 2)
{
if (parent->_right->_bf == 0)
{
Node* p = parent;
Node* p_r = p->_right;
RotateL(parent);
p->_bf = 1;
p_r->_bf = -1;
break;
}
else if (parent->_right->_bf == 1)
{
Node* p = parent;
Node* p_r = parent->_right;
RotateL(parent);
p->_bf = 0;
p_r->_bf = 0;
cur = p_r;
parent = p_r->_parent;
}
else//parent->_right->_bf == -1
{
Node* p = parent;
Node* p_r = parent->_right;
Node* p_r_l = p_r->_left;
RotateRL(parent);
p_r_l->_bf = 0;
p->_bf = _Height(p->_right) - _Height(p->_left);
p_r->_bf = _Height(p_r->_right) - _Height(p_r->_left);
cur = p_r_l;
parent =p_r_l->_parent;
}
}
else if (parent->_bf == -2)
{
if (parent->_left->_bf == 0)
{
Node* p = parent;
Node* p_l = parent->_left;
RotateR(parent);
p->_bf = -1;
p_l->_bf = 1;
break;
}
else if (parent->_left->_bf == 1)
{
Node* p = parent;
Node* p_l = parent->_left;
Node* p_l_r = p_l->_right;
RotateLR(parent);
p_l_r->_bf = 0;
p_l->_bf = _Height(p_l->_right) - _Height(p_l->_left);
p->_bf = _Height(p->_right) - _Height(p->_left);
cur = p_l_r;
parent = p_l_r->_parent;
}
else // == -1
{
Node* p = parent;
Node* p_l = parent->_left;
RotateR(parent);
p->_bf = 0;
p_l->_bf = 0;
cur = p_l;
parent = p_l->_parent;
}
}
else//意外处理
{
//cout << "平衡因子的绝对值超过2" << endl;
assert(false);
}
}
delete needDelete;
return true;
}
3. AVL树整体代码
#pragma once
#include <iostream>
#include <time.h>
#include <assert.h>
#include <string>
#include <vector>
#include <map>
#include <cstdlib>
#include <set>
#include <list>
#include <algorithm>
using namespace std;
namespace myAVLTree
{
template <class K, class V>
struct AVLTreeNode
{
AVLTreeNode(const pair<K, V>& kv)
:_kv(kv), _left(nullptr), _right(nullptr), _parent(nullptr),_bf(0)
{}
//三叉链
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
pair<K, V> _kv;
//平衡因子:右 - 左,平衡因子的绝对值 ≤ 1
int _bf;
};
template <class K, class V>
class AVLTree
{
typedef AVLTreeNode<K, V> Node;
public:
AVLTree()
:_root(nullptr)
{}
AVLTree(const AVLTree<K,V>& tree)
{
_root = _Copy(tree._root, nullptr);
}
AVLTree<K, V>& operator=(AVLTree<K, V> tree)
{
//利用临时变量出作用域销毁
swap(_root, tree._root);
return *this;
}
~AVLTree()
{
_destroy(_root);
_root = nullptr;
}
bool insert(const pair<K, V>& kv)
{
//插入一个节点,会影响部分祖先节点的平衡因子
//插入在左子树,平衡因子--
//插入在右子树,平衡因子++
//是否继续往上更新祖先的平衡因子,需要看parent的子树的高度是否变化:
//1. parent的平衡因子 == 0
//说明parent的平衡因子更新前是1/-1,插入节点插入矮的一边,parent所在子树高度不变,不需要继续往上更新
//2. parent的平衡因子 == 1/-1
// 说明parent的平衡因子更新前是0,插入节点插入任意一边,parent所在子树高度都会变化,需要继续向上更新
//3. parent的平衡因子 == 2/-2
//说明parent的平衡因子更新前是1/-1,插入节点插入在高的那边,进一步加剧parent所在的子树的平衡,违反AVL规则,需要旋转处理
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
//查找
while (cur)
{
if (kv.first > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (kv.second < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else
//key重复
return false;
}
//插入
cur = new Node(kv);
if (kv.first > parent->_kv.first)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
//更新平衡因子_bf
while (parent)
{
//更新_bf
if (cur == parent->_left)
parent->_bf--;
else
parent->_bf++;
//没有增高,就不需要向上更新了
if (parent->_bf == 0)
break;
//增高了,需要继续向上更新_bf
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
parent = parent->_parent;
}
//增高了,_bf == 2,AVL树不平衡了,需要旋转了
else if (parent->_bf == 2 || parent->_bf == -2)
{
//四种情况
//右旋
if (parent->_bf == -2 && cur->_bf == -1)
RotateR(parent);
//左旋
else if (parent->_bf == 2 && cur->_bf == 1)
RotateL(parent);
//左旋+右旋
else if (parent->_bf == -2 && cur->_bf == 1)
RotateLR(parent);
//右旋+左旋
else if (parent->_bf == 2 && cur->_bf == -1)
RotateRL(parent);
//旋转后该子树的根的_bf == 0,不需要再向上更新_bf了
break;
}
else//意外处理
{
//cout << "平衡因子的绝对值超过2" << endl;
assert(false);
}
}
return true;
}
Node* find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (key > cur->_kv.first)
cur = cur->_right;
else if (key < cur->_kv.first)
cur = cur->_left;
else
return cur;
}
//key不存在
return nullptr;
}
bool erase(const K& key)
{
if (_root == nullptr)
return false;
//查找
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (key > cur->_kv.first)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_kv.first)
{
parent = cur;
cur = cur->_left;
}
else //key == cur->_kv.first
break;
}
//判断cur是否为空,空表示不存在
if (cur == nullptr)
return false;
//key找到了,进行删除,删除有4种情况
//
//删除节点没有孩子节点
//删除节点只有一个右孩子节点
if (cur->_left == nullptr)
{
//cur是根节点
if (parent == nullptr)
{
_root = cur->_right;
if(_root != nullptr)
_root->_parent = nullptr;
//bf不变
delete cur;
return true;
}
//不是根节点
else
{
//删除节点是parent的左边
if (cur == parent->_left)
{
parent->_left = cur->_right;
if (cur->_right != nullptr)
cur->_right->_parent = parent;
parent->_bf++;
}
//删除节点是parent的右边
else if (cur == parent->_right)
{
parent->_right = cur->_right;
if (cur->_right != nullptr)
cur->_right->_parent = parent;
parent->_bf--;
}
}
}
//删除节点只有一个左孩子
else if (cur->_right == nullptr)
{
//cur是根节点
if (parent == nullptr)
{
_root = cur->_left;
if(_root != nullptr)
_root->_parent = nullptr;
//bf不变
delete cur;
return true;
}
//cur不是根节点
else
{
//删除节点是parent的左节点
if (cur == parent->_left)
{
parent->_left = cur->_left;
if (cur->_left != nullptr)
cur->_left->_parent = parent;
parent->_bf++;
}
else if (cur == parent->_right)
{
parent->_right = cur->_left;
if (cur->_left != nullptr)
cur->_left->_parent = parent;
parent->_bf--;
}
}
}
//删除节点有两个孩子节点
else
{
Node* minNode = cur->_right;
Node* minNodeParent = cur;
while (minNode->_left != nullptr)
{
//最左就是最小节点
minNodeParent = minNode;
minNode = minNode->_left;
}
//覆盖cur的kv
cur->_kv = minNode->_kv;
//删除最小节点
if (minNode == minNodeParent->_left)
{
minNodeParent->_left = minNode->_right;
if (minNode->_right != nullptr)
minNode->_right->_parent = minNodeParent;
minNodeParent->_bf++;
cur = minNode;
parent = minNodeParent;
}
else//注意这个情况--cur就是minNodeParent
{
minNodeParent->_right = minNode->_right;
if (minNode->_right != nullptr)
minNode->_right->_parent = minNodeParent;
minNodeParent->_bf--;
cur = minNode;
parent = minNodeParent;
}
}
Node* needDelete = cur;
//更新平衡因子_bf
//删除一个节点,parent所在子树不一定全部都矮一节
//第一次不需要改变parent的bf,因为上面删除操作时就改变了parent的bf,第一次只需要判断是否需要向上改变bf或旋转操作
bool flag_first = false;
while (parent)
{
if(flag_first)
{
//更新_bf
if (cur == parent->_left)
//减去-1等于+1
parent->_bf++;
else
parent->_bf--;
}
flag_first = true;
//删除后为1/-1,整体最高高度不变,不需要继续向上更新
if (parent->_bf == 1 || parent->_bf == -1)
break;
//删除后为0,说明整体高度变矮了
else if (parent->_bf == 0)
{
cur = parent;
parent = parent->_parent;
}
//_bf == 2,AVL树不平衡了,需要旋转了
else if (parent->_bf == 2)
{
if (parent->_right->_bf == 0)
{
Node* p = parent;
Node* p_r = p->_right;
RotateL(parent);
p->_bf = 1;
p_r->_bf = -1;
break;
}
else if (parent->_right->_bf == 1)
{
Node* p = parent;
Node* p_r = parent->_right;
RotateL(parent);
p->_bf = 0;
p_r->_bf = 0;
cur = p_r;
parent = p_r->_parent;
}
else//parent->_right->_bf == -1
{
Node* p = parent;
Node* p_r = parent->_right;
Node* p_r_l = p_r->_left;
RotateRL(parent);
p_r_l->_bf = 0;
p->_bf = _Height(p->_right) - _Height(p->_left);
p_r->_bf = _Height(p_r->_right) - _Height(p_r->_left);
cur = p_r_l;
parent =p_r_l->_parent;
}
}
else if (parent->_bf == -2)
{
if (parent->_left->_bf == 0)
{
Node* p = parent;
Node* p_l = parent->_left;
RotateR(parent);
p->_bf = -1;
p_l->_bf = 1;
break;
}
else if (parent->_left->_bf == 1)
{
Node* p = parent;
Node* p_l = parent->_left;
Node* p_l_r = p_l->_right;
RotateLR(parent);
p_l_r->_bf = 0;
p_l->_bf = _Height(p_l->_right) - _Height(p_l->_left);
p->_bf = _Height(p->_right) - _Height(p->_left);
cur = p_l_r;
parent = p_l_r->_parent;
}
else // == -1
{
Node* p = parent;
Node* p_l = parent->_left;
RotateR(parent);
p->_bf = 0;
p_l->_bf = 0;
cur = p_l;
parent = p_l->_parent;
}
}
else//意外处理
{
//cout << "平衡因子的绝对值超过2" << endl;
assert(false);
}
}
delete needDelete;
return true;
}
void InOrder()
{
_InOrder(_root);
}
bool IsAVLTree()
{
return _IsAVLTree(_root);
}
private:
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
//cout << root->_kv.first << ':' << root->_kv.second << " bf:" << root->_bf << endl;
cout << root->_kv.first << ':' << root->_kv.second << endl;
_InOrder(root->_right);
}
//计算高度
int _Height(Node* root)
{
if (root == nullptr)
return 0;
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
return max(leftHeight,rightHeight) + 1;
}
//判断AVL树的子函数
bool _IsAVLTree(Node* root)
{
if (root == nullptr)
return true;
int leftHeight = _Height(root->_left);
int rightHeight = _Height(root->_right);
//右 - 左
int diff = rightHeight - leftHeight;
//判断高度
if (diff != root->_bf || diff > 1 || diff < -1)
return false;
//if (diff != root->_bf)
//{
// cout << "diff 与 bf不匹配" << endl;
// return false;
//}
//if (diff > 1 || diff < -1)
//{
// cout << "bf绝对值超过1" << endl;
// return false;
//}
return _IsAVLTree(root->_left) && _IsAVLTree(root->_right);
}
//左旋
void RotateL(Node* parent)
{
Node* parent_R = parent->_right;
Node* parent_R_L = parent_R->_left;
parent->_right = parent_R_L;
if (parent_R_L != nullptr)
parent_R_L->_parent = parent;
Node* parent_parent = parent->_parent;
parent_R->_left = parent;
parent->_parent = parent_R;
//parent_R更新后是根节点
if (parent_parent == nullptr)
{
_root = parent_R;
parent_R->_parent = nullptr;
}
//parent_R 更新后不是根节点,可能属于上层节点的左节点或右节点
else
{
if (parent == parent_parent->_left)
{
parent_R->_parent = parent_parent;
parent_parent->_left = parent_R;
}
else
{
parent_R->_parent = parent_parent;
parent_parent->_right = parent_R;
}
}
parent->_bf = parent_R->_bf = 0;
}
//右旋
void RotateR(Node* parent)
{
Node* parent_L = parent->_left;
Node* parent_L_R = parent_L->_right;
parent->_left = parent_L_R;
if(parent_L_R != nullptr)
parent_L_R->_parent = parent;
Node* parent_parent = parent->_parent;
parent_L->_right = parent;
parent->_parent = parent_L;
//parent_L更新后是根节点
if (parent_parent == nullptr)
{
_root = parent_L;
parent_L->_parent = nullptr;
}
//parent_L 更新后不是根节点,可能属于上层节点的左节点或右节点
else
{
if (parent == parent_parent->_left)
{
parent_L->_parent = parent_parent;
parent_parent->_left = parent_L;
}
else
{
parent_L->_parent = parent_parent;
parent_parent->_right = parent_L;
}
}
//更新_bf
parent->_bf = parent_L->_bf = 0;
}
//右旋+左旋
void RotateRL(Node* parent)
{
Node* parent_R = parent->_right;
Node* parent_R_L = parent_R->_left;
int bf = parent_R_L->_bf;
RotateR(parent_R);
RotateL(parent);
//更新_bf
if (bf == 0)
{
parent->_bf = 0;
parent_R->_bf = 0;
parent_R_L->_bf = 0;
}
else if (bf == 1)
{
parent->_bf = -1;
parent_R->_bf = 0;
parent_R_L->_bf = 0;
}
else if (bf == -1)
{
parent_R->_bf = 1;
parent->_bf = 0;
parent_R_L->_bf = 0;
}
else//意外处理
{
cout << "bf超出2" << endl;
assert(false);
}
}
//左旋+右旋
void RotateLR(Node* parent)
{
Node* parent_L = parent->_left;
Node* parent_L_R = parent_L->_right;
int bf = parent_L_R->_bf;
RotateL(parent_L);
RotateR(parent);
//更新_bf
if (bf == 0)
{
parent->_bf = 0;
parent_L->_bf = 0;
parent_L_R->_bf = 0;
}
else if (bf == -1)
{
parent->_bf = 1;
parent_L->_bf = 0;
parent_L_R->_bf = 0;
}
else if (bf == 1)
{
parent_L->_bf = -1;
parent->_bf = 0;
parent_L_R->_bf = 0;
}
else//意外处理
{
//cout << "bf超过2" << endl;
assert(false);
}
}
void _destroy(Node* _root)
{
if (_root == nullptr)
return;
_destroy(_root->_left);
_destroy(_root->_right);
delete _root;
}
Node* _Copy(Node* root, Node* newRootParent)
{
if (root == nullptr)
return nullptr;
Node* newRoot = new Node(root->_kv);
newRoot->_left = _Copy(root->_left, newRoot);
newRoot->_right = _Copy(root->_right, newRoot);
newRoot->_bf = root->_bf;
newRoot->_parent = newRootParent;
return newRoot;
}
private:
Node* _root;
};
}
4. AVL树的性能
AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这
样可以保证查询时高效的时间复杂度,即O()。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。