一.AVL树的旋转
AVL树是平衡搜索二叉树的一种。
平衡因子:节点右树的高度减左树的高度,AVL树规定平衡因子的绝对值小于2。若不在这个范围内,说明该树不平衡。
AVL树节点:
struct AVLTreeNode
{
AVLTreeNode(const T& data = T())
: _pLeft(nullptr)
, _pRight(nullptr)
, _pParent(nullptr)
, _data(data)
, _bf(0)
{}
AVLTreeNode<T>* _pLeft;
AVLTreeNode<T>* _pRight;
AVLTreeNode<T>* _pParent;
T _data;
int _bf; // 节点的平衡因子
};
如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构, 使之平衡化。根据节点插入位置的不同,AVL树的旋转分为四种:
1. 新节点插入较高左子树的左侧---左左:右单旋
void RotateL(Node* pParent)
{
Node* SubR = pParent->_pRight;
Node* SubRL = SubR->_pLeft;
pParent->_pRight = SubRL;
if (SubRL)
SubRL->_pParent = pParent;
SubR->_pLeft = pParent;
pParent->_pParent = SubR;
if (pParent->_pParent == nullptr)
{
_pRoot = SubR;
SubR->_pParent = nullptr;
}
else
{
if (pParent->_pParent->_pLeft == pParent)
{
pParent->_pParent->_pLeft = SubR;
}
else
{
pParent->_pParent->_pRight = SubR;
}
}
SubR->_bf = SubRL->_bf = 0;
}
2. 新节点插入较高右子树的右侧---右右:左单旋
void RotateR(Node* pParent)
{
Node* SubL = pParent->_pLeft;
Node* SubLR = SubL->_pRight;
pParent->_pLeft = SubLR;
if(SubLR)
SubLR->_pParent = pParent;
SubL->_pRight = pParent;
pParent->_pParent = SubL;
if (pParent->_pParent == nullptr)
{
_pRoot = SubL;
SubL->_pParent = nullptr;
}
else
{
if (pParent == pParent->_pParent->_pRight)
{
pParent->_pParent->_pRight = SubL;
}
else
{
pParent->_pParent->_pLeft = SubL;
}
SubL->_pParent = pParent->_pParent;
}
SubL->_bf = SubLR->_bf = 0;
}
3. 新节点插入较高左子树的右侧---左右:先左单旋再右单旋
void RotateLR(Node* pParent)
{
Node* SubL = pParent->_pLeft;
Node* SubLR = SubL->_pRight;
RotateL(SubL);
RotateR(pParent);
if (SubLR->_bf == -1)
{
SubL->_bf = 0;
SubLR->_bf = 0;
pParent->_bf = 1;
}
else if (SubLR->_bf == 1)
{
SubL->_bf = -1;
SubLR->_bf = 0;
pParent->_bf = 0;
}
else
{
assert(false);
}
}
4. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋
void RotateRL(Node* pParent)
{
Node* SubR = pParent->_pRight;
Node* SubRL = SubR->_pLeft;
RotateR(SubR);
RotateL(pParent);
if (SubRL->_bf == 1)
{
SubR->_bf = 0;
pParent->_bf = -1;
SubRL = 0;
}
else if(SubRL->_bf == 0)
{
SubR->_bf = 0;
pParent->_bf = 0;
SubRL = 0;
}
else if (SubRL->_bf == -1)
{
SubR->_bf = 1;
pParent->_bf = 0;
SubRL = 0;
}
else
{
assert(false);
}
}
二.AVL树的插入
插入一个节点后平衡因子可能会改变。所以不仅要改变指针方向,还要更新平衡因子的值。
bool Insert(const T& data)
{
if (_pRoot == nullptr)
{
_pRoot = new Node(data);
return true;
}
Node* cur = _pRoot;
Node* parent = _pRoot;
while (cur)
{
if (data < cur->_data)
{
parent = cur;
cur = cur->_pLeft;
}
else if (data < cur->_data)
{
parent = cur;
cur = cur->_pRight;
}
else
{
return false;
}
}
cur = new Node(data);
if (data < parent->_data)
{
parent->_pLeft = cur;
}
else
{
parent->_pRight = cur;
}
//更新平衡因子
while (parent)
{
if (parent->_pLeft = cur)
{
parent->_bf-- ;
}
else
{
parent->_bf++;
}
if (parent->_bf == 1 || parent->_bf == -1)
{
cur = parent;
parent = parent->_pParent;
}
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)
{
RotateRL(parent);
}
else
{
RotateLR(parent);
}
}
else
{
assert(false);
}
}
return true;
}
三.AVL树的验证
1.求树的高度
size_t _Height(Node* pRoot)
{
if (pRoot == nullptr)
{
return 0;
}
int LestTreeHeight = _Height(pRoot->_pLeft);
int RightTreeHeight = _Height(pRoot->_pRight);
return LestTreeHeight > RightTreeHeight ? LestTreeHeight + 1 : RightTreeHeight + 1;
}
2.验证是否为平衡二叉树
bool _IsAVLTree(Node* pRoot)
{
if (pRoot == nullptr)
{
return true;
}
int LestTreeHeight = _Height(pRoot->_pLeft);
int RightTreeHeight = _Height(pRoot->_pRight);
int diff = RightTreeHeight - LestTreeHeight;
if (abs(diff) >= 2 || abs(diff) != pRoot->_bf)
{
return false;
}
return _IsAVLTree(pRoot->_pLeft) && _IsAVLTree(pRoot->_pRight);
}
3.测试用例验证
int main()
{
int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16,14 };
AVLTree<int> a;
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]);i++)
{
a.Insert(i);
}
cout << a.IsAVLTree() << endl;
return 0;
}