Table of contents
1. AVL tree - height balanced binary search tree
1.2 Definition of AVL tree node - triple chain
Major events in the world must be done in detail!
foreword
AVLtree is a binary search tree with "additional balance conditions". The establishment of its balance condition is to ensure that the depth of the whole tree is O(logN). Intuitively, the optimal balance condition is that the left and right subtrees of each node have the same height, but this is too strict, and it is difficult for us to insert new elements while maintaining such a balance condition. AVLtree then takes the next best thing, requiring that the height difference between the left and right subtrees of any node is at most 1. This is a weaker condition, but still guarantees a "log-depth" equilibrium state.
1. AVL tree - height balanced binary search tree
1.1 The concept of AVL tree
Balance factor: right subtree height - left subtree height
- Its left and right subtrees are both AVL trees
- The absolute value of the difference between the heights of the left and right subtrees (referred to as the balance factor) does not exceed 1 (-1/0/1)
1.2 Definition of AVL tree node - triple chain
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;
AVLTreeNode(const pair<K, V>& kv)
:_left(nullptr),
_right (nullptr),
_parent (nullptr),
_kv (kv),
_bf (0)
{}
};
2. AVL tree insertion
- Insert new nodes in the way of binary search tree
- Adjust the balance factor of the node
Insertion affects his ancestors (parent path), the height of the left subtree has changed, parent->_bf--; the height of the right subtree has changed, parent->_bf++
The front of the insert operation is the same as the binary search tree, with an additional cur->_parent pointing to the parent operation.
Re-control balance: update balance factor.
Rules for updating balance factors:
1. Newly added on the right, parent->_bf++; newly added on the left, parent->_bf--
2. After the update, parent->_bf == 1 or -1 , indicating that the balance factor of the parent before insertion is 0, indicating that the heights of the left and right subtrees are equal, and now one side is taller after insertion, and the height of the parent has changed, so it needs to continue to be updated
3. After the update, parent->_bf == 0 , indicating that the balance factor of the parent before insertion is 1 or -1, indicating that one side of the left and right subtrees is higher and the other is lower. Now after insertion, both sides are the same height, and the insertion fills in the short side , the height of the subtree where the parent is located remains unchanged, and there is no need to continue to update
4. After the update, parent->_bf == 2 or -2 , indicating that the balance factor of the parent before insertion is 1 or -1, which has already balanced the critical value. After insertion, it becomes 2 or -2, which breaks the balance and the child where the parent is located Trees need to be rotated .
Here are a few examples (all without rotation): the worst case to the root node (ie parent==nullptr)
Code:
//控制平衡因子
while (parent)
{
if (cur == parent->_left)
{
parent->_bf++;
}
else
{
parent->_bf--;
}
//插入后为0,说明插入前为1/-1,说明高度不一致,但是插入必定向矮的那端插入,插入后高度一致
if (parent->_bf == 0)
{
break;
}
//插入后为1/-1,说明插入前为0,说明高度一致,现在高度改变,向上更新
else if (abs(parent->_bf) == 1)
{
parent = parent->_parent;
cur = cur->_parent;
}
//插入后为2,打破平衡,需要旋转处理
else if (abs(parent->_bf == 2))
{
if (parent->_bf == 2 && cur->_bf == 1)
{
RotateL(parent);
}
else if (parent->_bf == -2 && cur->_bf == -1)
{
RotateR(parent);
}
else if (parent->_bf == -2 && cur->_bf == 1)
{
RotateLR(parent);
}
break;
}
else
{
assert(false);
}
}
}
2.1 Rotation of AVL tree
AVL tree balance condition: the difference between the left and right subtree heights of any node is at most 1
When parnt->_bf==2 or -2 after updating, the balance critical value is broken, and a rotation operation is required at this time.
Rotation principle:
a. Rotate into a balanced tree b. Keep search tree rules
There are 4 types of rotation:
1. Left single rotation
2. Right single rotation
3. Left and right double rotation
4. Right-left birotation
Among them (1, 2) are symmetrical to each other, called the outside (outside) insertion. (3, 4) are symmetrical to each other and are called inside insertions.
2.1.1 A new node is inserted into the right side of the higher right subtree --- right right: left single rotation
In the above figure, before insertion, the AVL tree is balanced, and the new node is inserted into the right subtree of 60 ( note: this is not the right child ), and a layer is added to the right subtree of 60, resulting in an unbalanced binary tree rooted at 30 , to make 30 balanced, only the height of the right subtree of 30 can be reduced by one level, and the height of the left subtree can be increased by one level.
The right subtree is about to be lifted up, so that 30 is turned down, because 30 is smaller than 6 0 , it can only be placed in the left subtree of 6 0 , and if 6 0 has a left subtree, the value of the root of the left subtree must be greater than 30 , less than 60 , it can only be placed in the right subtree of 30 , after the rotation is completed, just update the balance factor of the node. During rotation, there are several situations to consider:1. The left child of node 60 may or may not exist2. 30 may be the root node or a subtreeIf it is the root node, after the rotation is complete, the root node should be updatedIf it is a subtree, it may be the left subtree of a node, or it may be the right subtree
Figurative image:
Code:
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
//根左旋,压下去,连接subRL
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
//记录下parent的父节点
Node* ppNode = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
//如果根结点是父节点
if (_root == parent)
{
_root = subR;
subR->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = subR;
}
else
{
ppNode->_right = subR;
}
subR->_parent = ppNode;
}
subR->_bf = parent->_bf = 0;
}
2.1.2 A new node is inserted to the left side of the higher left subtree --- left left: right single rotation (logic same as left single rotation)
In the above figure, before insertion, the AVL tree is balanced. The new node is inserted into the left subtree of 30 ( note: this is not the left child ) , and the left subtree of 30 adds a layer, resulting in an unbalanced binary tree rooted at 60. , to make 60 balance, we can only reduce the height of the left subtree of 60 by one level, and increase the height of the right subtree by one level, that is, lift the left subtree up, so that 60 can be rotated down, because 60 is larger than 30 , we can only put it down In the right subtree of 30 , if 30 has a right subtree, the value of the root of the right subtree must be greater than 30 and less than 60 , and it can only be placed in the left subtree of 60. After the rotation is completed, the balance factor of the update node is Can. During rotation, there are several situations to consider:
1. The right child of node 30 may or may not exist2. 60 may be the root node or a subtreeIf it is the root node, after the rotation is complete, the root node should be updatedIf it is a subtree, it may be the left subtree of a node, or it may be the right subtree
example:
In the lateral insertion state, the only case of K2 "balanced before insertion, unbalanced after insertion" is shown on the left side of the figure. The A subtree grows one level, making it 2 deeper than the C subtree. It is impossible for the B subtree to be at the same level as the A subtree, otherwise k2 would be in an unbalanced state before insertion. It is also impossible for the B subtree to be at the same level as the C subtree, otherwise the first violation of the balance condition will be k1 instead of k2.
In order to adjust the balance state, we hope to raise the A subtree by one level and drop the C subtree by one level—this is already a step further than the balance condition required by the AVL-tree. The right side of the figure is the adjusted situation. We can imagine this way, lift k1 up, make k2 slide down naturally, and hang the B subtree to the left of k2. This is done because the rules of the binary search tree let us know that k2>k1, so k2 must become the right child of k1 in the new tree. The rules of the binary search tree also tell us that the key values of all nodes of the B subtree are between k1 and k2, so the B subtree in the new tree shape must fall to the left of k2.
Code:
void RotateR(Node* parent)
{
Node* subL = parent->_right;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* ppNode = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (_root == parent)
{
_root = subL;
subL->_parent = nullptr;
}
else
{
if (ppNode->_left == parent)
{
ppNode->_left = subL;
}
else
{
ppNode->_right = subL;
}
subL->_parent = ppNode;
}
subL->_bf = parent->_bf = 0;
}
2.1.3 The new node is inserted into the right side of the higher left subtree --- left and right: first left single rotation and then right single rotation
Turn the double rotation into a single rotation and then rotate, that is: first perform a left single rotation on 30, and then perform a right single rotation on 90, and then consider updating the balance factor after the rotation is completed (the balance factor is not fixed, because it may be in b Insert, it may also be inserted at c, or it may be h=0, inserted at the right of 30). The balance factor of 60 before the rotation is the basis for judgment, and the judgment is recorded.
Figurative image:
Code:
void RotateLR(Node* parent)
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
if (bf == 1)
{
subL->_bf = -1;
parent->_bf = 0;
}
else if (bf == -1)
{
subL->_bf = 0;
parent->_bf = 1;
}
else if (bf == 0)
{
subL->_bf = parent->_bf = 0;
}
else
{
assert(false);
}
}
2.1.4 The new node is inserted into the left side of the higher right subtree --- right left: first right single rotation and then left single rotation
Summarize:
If the subtree rooted at pParent is unbalanced, that is, the balance factor of pParent is 2 or -2, consider the following situations1. The balance factor of pParent is 2, indicating the height of the right subtree of pParent, and the root of the right subtree of pParent is pSubRLeft single rotation is performed when the balance factor of pSubR is 1Right-left double rotation is performed when the balance factor of pSubR is -12. The balance factor of pParent is -2, indicating the height of the left subtree of pParent, and the root of the left subtree of pParent is pSubLWhen the balance factor of pSubL is -1, perform right single rotationWhen pSubL has a balance factor of 1, left and right double rotation is performedAfter the rotation is completed, the height of the subtree rooted at the original pParent is reduced, and it has been balanced, so no upward update is required.
The value and significance of rotation:
1. balance
2. Reduce the height (restore to the appearance before insertion)