概念
平衡因子
6.向上更新平衡因子时,当parent的平衡因子为0时,不需要再向上更新(同4)
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;
private:
Node* _root = nullptr;
public:
bool Insert(const pair<K, V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
parent = cur;
if (cur->_kv.first < kv.first)
{
cur = cur->_right;
}
else if (cur->_kv.first > kv.first)
{
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(kv);
if (parent->_kv.first > cur->_kv.first)
{
parent->_left = cur;
}
else
{
parent->_right = cur;
}
cur->_parent = parent;
//处理平衡(旋转)
//1.向上更新节点平衡因子
//2.遇到平衡因子的绝对值为2时,停止更新
//3.开始旋转
return true;
}
};
因子更新
while (parent)
{
if (parent->_left == cur)
{
parent->_bf--;
}
else if (parent->_right == cur)
{
parent->_bf++;
}
else
{
assert(false);
}
if (parent->_bf == 0)
{
break;
}
else if (parent->_bf == 1 || parent->_bf == -1)
{
cur = cur->_parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2)
{
//旋转
break;
}
else
{
//说明该树在插入之前就不是AVLTree
assert(false);
}
}
旋转(4种)
左单旋
void RotateL(Node* parent)
{
Node* cur = parent->_right;
Node* ocl = cur->_left;
Node* op = parent;
Node* oc = cur;
Node* opp = parent->_parent;
if (opp == nullptr)
{
_root = oc;
}
else
{
if (opp->_left == op)
{
opp->_left = oc;
}
else
{
opp->_right = oc;
}
}
if (ocl != nullptr)
{
ocl->_parent = op;
}
op->_right = ocl;
op->_parent = oc;
oc->_left = op;
oc->_parent = opp;
oc->_bf = op->_bf = 0;
}
右单旋
void RotateR(Node* parent)
{
Node* cur = parent->_left;
Node* ocr = cur->_right;
Node* op = parent;
Node* oc = cur;
Node* opp = parent->_parent;
if (opp == nullptr)
{
_root = oc;
}
else
{
if (opp->_left == op)
{
opp->_left = oc;
}
else
{
opp->_right = oc;
}
}
if (ocr != nullptr)
{
ocr->_parent = op;
}
oc->_right = op;
oc->_parent = opp;
op->_left = ocr;
op->_parent = oc;
oc->_bf = op->_bf = 0;
}
双旋
1.左右旋
规律总结:
- 更新后节点60的平衡因子总为0;
- 由图知道,可用插入未旋转时60的平衡因子来区分三种情况;
- 1)0;
- 2)-1;
- 3)1;
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 == 0)
{
subL->_bf = parent->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
parent->_bf = 1;
}
else if (bf == 1)
{
subL->_bf = -1;
parent->_bf = 0;
}
else
{
assert(false);
}
}
2.右左旋
具体方法和左右旋类似,方向变了而已,不做赘述;
//右左旋
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 == 0)
{
subR->_bf = parent->_bf = 0;
}
else if (bf == -1)
{
subR->_bf = 1;
parent->_bf = 0;
}
else if (bf == 1)
{
subR->_bf = 0;
parent->_bf = -1;
}
else
{
assert(false);
}
}
总结:
验证
public:
int Height()
{
return Height(_root);
}
bool IsBalance()
{
return IsBalance(_root);
}
private:
int Height(Node* root)
{
if (root == nullptr)
return 0;
return max(Height(root->_left), Height(root->_right)) + 1;
}
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);
}
删除
思想:与插入相反,当删除节点的父节点的平衡因子变为0时,旋转平衡因子;变为1或-1时,不需要变。
性能
AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间
复杂度,即logN。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比
较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会变),可以考虑AVL树,但一个结构经常修改,就不太适合。