AVL树概念
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查 找元素相当于在顺序表中搜索元素,效率低下。
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树: 它的左右子树都是AVL树 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
更新平衡因子的规则
平衡因子简称为bf
- 新增节点在右子树,parent->bf++ 新增节点在左子树,parent->bf--
- 更新后,parent->bf==1 or -1 表明插入前左右子树高度相等,插入后,parent的高度高了,需要向上继续更新。
- 更新后,parent->bf==0 表明插入前左右子树一高一低,插入后左右子树高度相同,parent的高度不变,不用再向上更新。
- 更新后,parent->bf==2 or -2 表明需要旋转parent所在的子树。
模拟实现AVL树
节点结构体
template<class K, class V>
struct AVLTreeNode
{
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
pair<K, V> _kv;
int _bf; // balance factor
AVLTreeNode(const pair<K, V>& kv)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _kv(kv)
, _bf(0)
{}
};
插入
template <class K,class V>
class AVLTree
{
typedef AVLTreeNode<K,V> Node;
public:
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
Node* cur = new Node(kv);
return true;
}
Node* paretn = nullptr;
Node* cur = _root;
while (cur)
{
//这里比较方法用first还是second看需求而定
if (cur->_kv.first > kv.first)
{
parent = cur;
cur = cur->left;
}
else if (cur->_kv.first < kv.first)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
//找到了空节点 把它插入AVL树
cur = new Node(kv);
//看他是左子树还是右子树
if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
cur->_parent = parent;
//插入完成 然后更新平衡因子
while (parent)//最多就更新到 _root _root的_parent==nullptr;
{
if (cur == parent->_left)
{
parent->_bf--;
}
else
{
parent->_bf++;
}
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//开始旋转parent所在的树,需要旋转处理
break;
}
else
{
assert(false);//直接报错
}
}
return true;
}
private:
_root == nullptr;
};
AVL树的旋转处理
情况一 新节点插入较高右子树的右侧
//新节点插入较高右子树的右侧 :左单旋
void RotateL(Node* parent)
{
Node* subR = parent->right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
{
subRL->_parent = parent;
}
Node* pparent = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (_root == parent)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (pparent->_left == parent)
pparent->_left = subR;
else
pparent->_left = subR;
}
subR->_parent = pparent;
subR->_bf = parent->_bf = 0;
}
情况二 新节点插入较高左子树的左侧
void RotateR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
{
subLR->_parent = parent;
}
Node* pparent = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (pparent->_left == parent)
pparent->_left = subL;
else
pparent->_right = subL;
subL->_parent = pparent;
}
subL->_bf = parent->_bf = 0;
}
情况三 新节点插入较高左子树的右侧
这里不管是插入b位置还是c位置,处理手段都一样
这里是穷举了subLR的_bf _bf==-1 _bf==1 _bf==0的这几种情况
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
subLR->_bf = 0;
if (bf == 1)
{
parent->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1)
{
parent->_bf = 1;
subL->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subL->_bf = 0;
}
else
{
assert(false);
}
}
情况四 新节点插入较高右子树的左侧
void RotateRL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
subRL->_bf = 0;
if (bf == 1)
{
subR->_bf = 0;
parent->_bf = -1;
}
else if (bf == -1)
{
subR->_bf = 1;
parent->_bf = 0;
}
else if (bf == 0)
{
parent->_bf = 0;
subR->_bf = 0;
}
else
{
assert(false);
}
}
相关测试
void TestAVLTree1()
{
int a[] = { 16,3,7,11,9,26,18,14,15 };
AVLTree<int, int> tree1;
for (auto& e : a)
{
tree1.Insert(make_pair(e, e));
}
tree1.InOrder();
}
template<class K, class V>
class AVLTreeNode
{
public:
//....
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool IsBalance()
{
return _IsBalance(_root);
}
private:
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_kv.first << ":" << root->_kv.second << endl;
_InOrder(root->_right);
}
bool _IsBalance(Node* root)
{
if (root == nullptr)
{
return true;
}
int leftHT = Height(root->_left);
int rightHT = Height(root->_right);
int diff = rightHT - leftHT;
if (diff != root->_bf)
{
cout << root->_kv.first << "平衡因子异常" << endl;
return false;
}
return abs(diff) < 2
&& _IsBalance(root->_left)
&& _IsBalance(root->_right);
}
int Height(Node* root)
{
if (root == nullptr)
return 0;
return max(Height(root->_left), Height(root->_right)) + 1;
}
};