目录
AVL树概念
当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1,超过1需要对树中的结点进行调整。即可降低树的高度,从而减少平均搜索长度。
一棵AVL树性质:
1.它的左右子树都是AVL(任意一个子树左右高度差都不超过1)
2.左右子树高度之差(简称平衡因子)的绝对值不超过1(平衡因子是其中一种实现方式,判断平衡因子即可判断是否为AVL树)
3.平衡因子 = 右子树高度 - 左子树高度
4.AVL树是一棵绝对平衡的二叉搜索树,查询的时间复杂度log2(N)。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时, 有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。
AVL树结构
引入平衡因子,需要三岔链,原因在于新插入节点还需保持AVL树的特性,新插入节点后平衡因子需要改变(更新新插入节点祖先路径)
template<class K,class V>
struct AVLTreeNode
{
AVLTreeNode<K, V>* _left;
AVLTreeNode<K, V>* _right;
AVLTreeNode<K, V>* _parent;
int _bf;//平衡因子
pair<K, V> _kv;
AVLTreeNode(const pair<K, V>& kv)
:_left(nullptr)
,_right(nullptr)
,_parent(nullptr)
,_kv(kv)
,_bf(0)
{}
};
template<class K,class V>
class AVLTree
{
public:
typedef AVLTreeNode<K, V> Node;
private:
Node* _root;
};
insert
插入后AVL树有可能导致不平衡,此时需要沿着parent更新平衡因子
更新平衡因子规则:
1.如果此时是在parent的右,parent平衡因子++
2.如果此时是在parent的左,parent平衡因子--
3.更新后parent平衡因子如果为0,说明之前是1--/-1++,代表左右子树一边高一边低。插入后变为0,表示两边子树一样高。此时parent则不用继续往上更新(左右子树平衡)
4.更新后parent平衡因子如果为1/-1,说明原来parent平衡因子只可能是0,0代表左右子树高度相等。更新完后为1/-1,代表左右子树一边高一边低,表示parent的高度也改变了,继续往上更新平衡因子(子树高度改变影响父亲)
5.更新后praent平衡因子如果为2/-2,此时parent所在的子树需要旋转处理
insert的基本逻辑,不包括旋转,旋转下面总结
bool insert(const pair<K,V>& kv)
{
if (_root == nullptr)
{
_root = new Node(kv);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
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;
}
}
cur = new Node(kv);
if (parent->_kv.first > kv.first)
{
parent->_left = cur;
}
else if (parent->_kv.first < kv.first)
{
parent->_right = cur;
}
cur->_parent = parent;
//while控制平衡因子,最坏的情况下,更新到根节点
while (parent)
{
if (parent->_left == cur)
{
parent->_bf--;
}
else if (parent->_right == cur)
{
parent->_bf++;
}
if (parent->_bf == 1 || parent->_bf == -1)
{
parent = parent->_parent;
cur = cur->_parent;//沿着三岔链往上走
}
else if (parent->_bf == 0)
{
break;
}
else if(parent->_bf == 2 || parent->_bf == -2)//parent所在子树不平衡,开始旋转
{
}
else
{
assert(false);//直接报错,插入之前平衡因子已经出问题
}
}
return true;
}