The AVL tree is a highly balanced two-fork search tree, with the height of the left and right trees of each node not greater than 1. This nature makes the search efficiency of the AVL tree higher than the average two-fork search tree, because for a set of incrementing arrays, the two-fork search tree is a linked list, the search time complexity is naturally o (n), and its composition of the AVL tree is certainly a search efficiency of O (LG (n)) two fork tree. Because of this, in order to maintain the nature of its balance, the insertion and deletion of AVL tree is more complex than the ordinary binary search tree.
Binary search tree can refer to the insertion and deletion of binary search tree
1. Maintain the balance of the AVL tree by rotating
The rotation is divided into left and right, both of which are symmetrical, as shown in the following figure.
After inserting or deleting a node, the AVL tree is rotated in a way that maintains its balance. For a tree with a left subtree 1 taller than the right subtree in the image below, if a node is inserted in its left subtree, it will cause the tree to be unbalanced. At this point, the tree can be balanced with one or two rotations.
When the node is inserted into the left sub-tree of the B-node, it is only necessary to make a right-turn to the tree A, as shown in the following figure, the rotated tree a Saozi the right sub-tree height will reach equilibrium.
When the node is inserted under the right subtree of the B-node, it is necessary to first turn the left rotation of tree B into the previous case and then the tree A to the right, as shown in the following figure.
After the left-hand rotation of tree B, tree B's Supi right subtree is 1 higher, which translates to the previous case (inserting the node into the left subtree of tree B), and then to the tree a once right to adjust the tree back to the equilibrium state. Why take a left-hand spin on tree B? Suppose we force Tree B left, directly to the tree a right-hand, the resulting tree will be as shown in the figure below.
The rotated tree did not become balanced. The reason is very simple, because when the right-hand tree A, the right subtree of tree B is transferred to tree A, which leads to the tree imbalance before and after the height of this tree is not changed, the tree is still unbalanced, so we need to first by the tree B to the tree B into a Supi right subtree high tree.
The right subtree of Node A is taller than the left subtree, and the node is inserted into the right subtree of Node A, which is completely symmetrical to the above situation.
Below is the code for the left and right of the AVL tree.
void Avlleftrotate (Tree *tree, Node *x) {leftrotate (tree, x);
X->height = Max (GetHeight (X->left), GetHeight (x->right)) + 1;
X->parent->height = x->height + 1; if (x->parent->parent! = NULL) {x->parent->parent->height = max (GetHeight (x->parent->parent-
>left), GetHeight (x->parent->parent->right)) + 1;
}} void Avlrightrotate (tree *tree, Node *x) {rightrotate (tree, x);
X->height = Max (GetHeight (X->left), GetHeight (x->right)) + 1;
X->parent->height = x->height + 1; if (x->parent->parent! = NULL) {x->parent->parent->height = max (GetHeight (x->parent->parent-
>left), GetHeight (x->parent->parent->right)) + 1;
}} void Leftrotate (Tree *tree, node *x) {Node *y = x->right;
X->right = y->left;
if (y->left! = Tree->nil && Y->left! = NULL) {y->left->parent = x;
} y->parent = x->parent; if (x->parent = = Tree->nil | | x->parent = = NULL) {tree->root = y;
} else if (x = = x->parent->left) {x->parent->left = y;
} else {x->parent->right = y;
} y->left = x;
X->parent = y;
Y->size = x->size;
X->size-= ((y->right! = Tree->nil && y->right! = NULL)? y->right->size:0) + 1;
} void Rightrotate (Tree *tree, node *x) {Node *y = x->left;
X->left = y->right;
if (y->right! = Tree->nil && y->right! = NULL) {y->right->parent = x;
} y->parent = x->parent;
if (x->parent = = Tree->nil | | x->parent = = NULL) {tree->root = y;
} else if (x = = x->parent->left) {x->parent->left = y;
} else {x->parent->right = y;
} y->right = x;
X->parent = y;
Y->size = x->size;
X->size-= ((Y->left! = Tree->nil && Y->left! = NULL)? y->left->size:0) + 1; }
In the code above, the node's Size property records how many nodes are in the subtree of the node, and the Height property is the tree height of the node.
2. Inserting a new node
The AVL tree after inserting the node may be unbalanced, and we need to rotate to keep the tree balanced. The workflow of the program is:
1). As with the normal two-fork search tree, insert the new node z into the appropriate position as the leaf node;
2). From node Z, go back up, if the parent node of Z zpp is not empty, then judge whether the ZPP is balanced, that is, if the high difference of Saozi right subtree of ZPP is not greater than 1, if the balance is from the parent node of Node Z ZP continue to backtrack, otherwise the balance of ZPP is adjusted by rotation;
3). To rotate the ZPP method is to add the zpp of the left Sub-tree Zl than the right sub-tree ZR High 2, and the Supi right sub-tree of ZL is high, you only need to zpp a right turn, if Zl Supi right sub-tree low, you have to ZL first left-handed, then zpp right-handed. ZPP of the Supi right subtree is 2 lower than the case of symmetric processing can be.
The method to get the tree height of a node is as follows.
int getheight (node *node)
{
if (node = = NULL) return-1;
Return node->height;
}
The method for inserting a new node is the same as for a normal two-fork search tree to insert nodes, as shown in the code below.
void Insertavltree (Tree *tree, int value)
{
Node *node = Createavlnode (value);
if (Tree->root = = NULL)
{
tree->root = node;
return;
}
Node *n = tree->root;
while (1)
{
n->size++;
if (value < N->value)
{
if (n->left = = NULL)
{
n->left = node;
Node->parent = n;
break;
}
n = n->left;
}
else
{
if (n->right = = NULL)
{
n->right = node;
Node->parent = n;
break;
}
n = n->right;
}
}
Avlinsertfixup (tree, node);
}
The key to the above code is that after the insertion node is complete, the newly inserted node node begins to retrace the balance of the tree upward. The code for the Avlinsertfixup method is as follows.
Update the tree height from the inserted new node and maintain the balance through the rotation node void Avlinsertfixup (Tree *tree, node *z) {Node *tmp = Z;
while (Z! = NULL) {z->height = max (GetHeight (Z->left), GetHeight (z->right)) + 1;
if (z->parent = null && z->parent->parent! = null) {Node *ZP = z->parent;
Node *zpp = zp->parent;
Zp->height = Max (GetHeight (Zp->left), GetHeight (zp->right)) + 1;
Zpp->height = Max (GetHeight (Zpp->left), GetHeight (zpp->right)) + 1; if (GetHeight (zpp->left)-getheight (zpp->right) = =-2) {//L-ZPP before making sure that the right tree of ZP is taller than the left tree high if (GetHeight (zp->
left) > GetHeight (zp->right) {avlrightrotate (tree, ZP);
} avlleftrotate (tree, ZPP); } else if (GetHeight (zpp->left)-getheight (zpp->right) = = 2) {//right-turn zpp before making sure that the left tree of ZP is taller than the right tree high if (getheigh
T (Zp->left) < GetHeight (zp->right)) {avlleftrotate (tree, ZP);
} avlrightrotate (tree, ZPP);
}} z = z->parent; }
}
The above code, while backtracking upward, adjusts the tree balance on demand while updating the height of each node.
3. Delete Nodes
Deleting a node can cause the tree's height to change, causing the tree to become unbalanced. The AVL tree Delete node executes the same process as the normal binary search tree, and then from the very beginning, the tree height changes from the node to the first because the node is deleted. The key to this operation is how to determine "the first node that has a high change in the tree". Because there are 3 kinds of deletion nodes in the common binary search tree, there are 3 scenarios for the AVL tree to determine the "first node with high tree height change". Suppose that the node being deleted is x.
1). x is the leaf node, "The first occurrence of the tree high-change node" is the parent node of X;
2). x there is only one child, "the first occurrence of a tree high-change node" is the parent node of X;
3). x has two children, then "the first occurrence of a tree high-change node" is the parent node of the posterior drive of X.
After determining the "first occurrence of a tree-high change", it is necessary to backtrack from the node, and, as with the insertion node, rotate the nodes along the road as needed.
The code to delete the node and adjust it after deleting the node is as follows. The following code uses a transplant method to delete a node from the migration tree. After deleting the node like the normal binary search tree, execute the Avldeletefixup method to adjust the tree height to achieve a balanced tree.
/** * Replace the *tree1 with Tree2, if the *tree1 is the root, then directly change the *tree1 point */void Transplant (Tree *tree, Node *tree1, node *tree2) {if (Tree1->pa
Rent = = NULL) {tree->root = Tree2;
Tree2->parent = NULL;
Return
} if (tree2! = NULL) Tree2->parent = tree1->parent;
if (tree1 = = tree1->parent->left) Tree1->parent->left = tree2;
else tree1->parent->right = tree2;
} void Deletefromavltree (Tree *tree, node *node) {if (node = = NULL) return;
Node *d = node->parent;
Node *n = node;
while (n->parent! = NULL) {n = n->parent;
n->size--;
} if (Node->left = = NULL) {Transplant (tree, node, node->right);
} else if (node->right = = NULL) {Transplant (tree, node, node->left);
} else {Tree t;
T.root = node->right;
Node *min = minimum (&t);
Node *end = min->right;
Min->size = node->size-1;
if (node = = tree->root) tree->root = min; if (node->right! = min) {Transplant (tree, Min, MIN->right);
Min->right = node->right;
node->right->parent = min;
D = min->parent;
} else {d = min;
} Min->left = node->left;
node->left->parent = min;
Transplant (tree, node, min);
n = min->right;
while (n! = end) {n->size--;
n = n->left;
}} avldeletefixup (tree, D);
Free (node);
}//From the parent node of the node that was actually deleted (because the height of the tree is likely to change from the beginning of the nodes), adjust the tree height and maintain the balance by rotation void Avldeletefixup (Tree *tree, Node *z) {while (Z! = NULL) {
Z->height = Max (GetHeight (Z->left), GetHeight (z->right)) + 1;
if (GetHeight (z->left)-getheight (z->right) = =-2) {Node *ZR = z->right;
if (GetHeight (zr->left) > GetHeight (zr->right)) {avlrightrotate (tree, ZR);
} avlleftrotate (tree, z);
} else if (GetHeight (z->left)-getheight (z->right) = = 2) {Node *zl = z->left;
if (GetHeight (Zl->left) < GetHeight (zl->right)) {Avlleftrotate (tree, ZL); } avlrightrotate (tree, z);
} z = z->parent; }
}
4. Time complexity of AVL tree operations
The insertion operation requires O (LG (n)) traversal time and a constant time of up to two rotations;
The delete operation requires O (LG (n)) traversal time and a number of times the constant time of rotation;
In general, the insertion and deletion of AVL trees requires only O (LG (n)) time, but their constant coefficients are different.
Finally, this blog has introduced and will introduce the data structure and algorithm C implementation code are here data structure and algorithm