# Balanced binary lookup tree -- AVL tree

Binary lookup tree: the value of each node of the tree is larger than all nodes on the left subtree and smaller than all nodes on the right subtree.

Define the height difference between the left subtree and the right subtree as the balance factor (BF) of the node

Balanced binary lookup tree (AVL tree): the absolute value of BF is less than or equal to 1. If the absolute value of the balance factor is greater than 1, it indicates that the tree is not a balanced binary tree. At this time, the structure of the tree needs to be readjusted

# Node rebalancing

When adding nodes, adjust the node position whenever the absolute value of the height difference between the left and right subtrees is 2. The height difference between the left and right subtrees is reduced by rotation.

## Dextral

The rotation process is shown in the figure below

Right rotation is required only when the height of the left subtree is higher than that of the right subtree. Right rotation reduces the height of the left subtree and increases the height of the right subtree.

Let the balance factor of node a be ABF, the balance factor of node L be Lbf, the bf value of subtree a be ABF, the bf value of subtree b be bbf, and the bf value of subtree c be cbf,

### Change of relationship between left and right subtrees

Transformation process of left and right subtrees in right rotation

①→②  A->lchild = L->rchild

②→③  L->rchild = A

### Equilibrium factor transformation

The change of BF (balance factor) during transformation is observed from ① to ③

① Medium: Abf  = max(abf, bbf) + 1 - cbf，Lbf  = abf  -  bbf

③ Medium: Lbf  = abf  - max(bbf, cbf) -1 ，Abf  = bbf  - cbf

The change results are shown in table (1):

code:

```void RightSingleRotate(struct Node **avltree){
int leftbalancefactor =  (*avltree)->lchild->balancefactor,treebalancefactor=(*avltree)->balancefactor;
struct Node *temp = (*avltree)->lchild;
(*avltree)->lchild = temp->rchild;
temp->rchild = (*avltree);
*avltree = temp;
switch(treebalancefactor){
case 2:
switch(leftbalancefactor){
case 2 :
(*avltree)->balancefactor = 0;
(*avltree)->rchild->balancefactor = -1;
break;
case 1 :
(*avltree)->balancefactor = 0;
(*avltree)->rchild->balancefactor = 0;
break;
case 0 :
(*avltree)->balancefactor = -1;
(*avltree)->rchild->balancefactor = 1;
break;
}
break;
case 1:
switch(leftbalancefactor){
case 1 :
(*avltree)->balancefactor = -1;
(*avltree)->rchild->balancefactor = -1;
break;
case 0 :
(*avltree)->balancefactor = -1;
(*avltree)->rchild->balancefactor = 0;
break;
}
break;
}
}```

## Sinistral

The rotation process is shown in the figure below

Left rotation is required only when the height of the right subtree is higher than that of the left subtree. Left rotation reduces the height of the right subtree and increases the height of the left subtree.

Let the balance factor of node a be ABF, the balance factor of node R be Rbf, the bf value of subtree a be ABF, the bf value of subtree b be bbf, and the bf value of subtree c be cbf,

### Change of relationship between left and right subtrees

Transformation process of left and right subtrees in right rotation

①→②  A->rchild = R->lchild

②→③  R->lchild = A

### Equilibrium factor transformation

The change of BF (balance factor) during transformation is observed from ① to ③

① Medium: Abf  = abf  - max(bbf, cbf) - 1 , Rbf  = bbf  - cbf

③ Medium: Rbf  =  max(abf, bbf) - cbf  + 1 , Abf  = abf  - bbf

The transformations are listed below (2):

Related code

```void LeftSingleRotate(struct Node **avltree){
int rightbalancefactor =  (*avltree)->rchild->balancefactor,treebalancefactor=(*avltree)->balancefactor;
struct Node *temp = (*avltree)->rchild;
(*avltree)->rchild = temp->lchild;
temp->lchild = (*avltree);
*avltree = temp;
switch(treebalancefactor){
case -2:
switch(rightbalancefactor){
case -2 :
(*avltree)->balancefactor = 0;
(*avltree)->lchild->balancefactor = 1;
break;
case -1 :
(*avltree)->balancefactor = 0;
(*avltree)->lchild->balancefactor = 0;
break;
case 0 :
(*avltree)->balancefactor = 1;
(*avltree)->lchild->balancefactor = -1;
break;
}
break;
case -1:
switch(rightbalancefactor){
case -1 :
(*avltree)->balancefactor = 1;
(*avltree)->lchild->balancefactor = 1;
break;
case 0 :
(*avltree)->balancefactor = 1;
(*avltree)->lchild->balancefactor = 0;
break;
}
break;
}
}```

## Left subtree rotation

If the balance factor of node A is 2, the left subtree needs to be rotated. Set the current node as A and the left child as L.

(1) Abf  = 1. Add / reduce nodes

• Lbf  = 0. Add a new node so that the height of a subtree increases by 1, indicating that there is abf = bbf before the new node  = cbf
• Lbf  = 1. Reduce nodes so that the height of c subtree is reduced by 1, indicating that there is abf - bbf before reducing nodes  = 1 , cbf  =  abf

Get Abf  = 2，Lbf  = one

(2) If Abf  = 1. Add / reduce nodes

• Lbf  = - 1. Reduce the nodes so that the height of the c subtree is reduced by 1, indicating that there is an error before reducing the nodes    bbf  - abf  = 1 , cbf  = bbf
• Lbf  = 0, add a node, b subtree height plus 1, indicating that there is a node before adding a node   abf  = bbf  = cbf

Get Abf  = 2，Lbf  = - one

(3) If Abf  = 1. Add / reduce nodes

• Lbf  = 0, reduce the nodes, so that the height of d subtree is reduced by 1, indicating that there is an error before reducing the nodes   abf  = bbf  = cbf

Get Abf  = 2，Lbf  = - one

### Scenario 1

Abf  = 1. If there is ABF after adding or deleting a node  = 2，Lbf  = one

Then, according to the rotation table result (1), there are   Abf  = 0, if Lbf  = 0, one right rotation can ensure the end of adjustment

Observe the change pattern of right rotation, and then consider the height, ha HB = 1, ha HC = 1. ① the height of the middle tree is ha+2, and ③ the height of the middle tree is ha+1,

• If the reason for the transformation is to add new nodes, the height of the subtree before those new nodes is ha+1, indicating that the height of the tree remains unchanged
• If the reason for the transformation is to reduce nodes, the height of the subtree before reducing nodes is ha+2, indicating that the height of the tree is reduced by 1

### Scenario 2

Abf  = 1. If there is ABF after adding or deleting a node  = 2，Lbf  = - 1，

According to the rotation table results (1) (2), there are   Abf  = 1. If Lbf  = - 2. One right rotation cannot solve the problem

Therefore, you can rotate the left node L of A first, and then rotate A right, as shown in the following figure:

① → ③: Lbf at this time  = - 1. If LRbf   ∈ {- 1,0,1}, after the left-handed transformation of the left subtree of A, there is LRbf   ∈   {1,2}

③ → ⑤: equivalent to ABF in Scene 1  = 2，Lbf  = 1. One right rotation can solve the problem, and finally   LRbf  = 0，Lbf   ∈ {0,1}，Abf   ∈ {-1,0}，

Considering the height, ha=max(hb,hc), hd=ha, the height of the tree in ① is ha+3, and the height of the tree in ⑤ becomes ha+2,

• If the reason for the transformation is to add new nodes, the height of the subtree before those new nodes is ha+2, indicating that the height of the tree remains unchanged
• If the reason for the transformation is to reduce nodes, the height of the subtree before reducing nodes is ha+3, indicating that the height of the tree is reduced by 1

### Scenario 3

Abf  = 1. If there is ABF after deleting a node  = 2，Lbf  = 0. According to the rotation table result (1), one right rotation can solve the problem

At this time, if the height of node a is h, the height of nodes b and c is h-1, the height of the root node before the transformation is h+2, and the height after the transformation is h+1

Considering the height, ha=hb, hc=ha-1, the height of ① middle tree is ha+2, and the height of ⑤ middle tree becomes ha+1,

• The reason for this scene transformation can only be to reduce nodes. Before reducing nodes, the height of this subtree is ha+2, indicating that the height of this tree is reduced by 1

code

```void ReBalanceAVLLeftTree(struct Node **avltree){
struct Node *L,*LR;
L = (*avltree)->lchild;
switch(L->balancefactor){
case 1:
RightSingleRotate(avltree);
break;
case -1:
LeftSingleRotate(&(*avltree)->lchild);
RightSingleRotate(avltree);
break;
case 0:
RightSingleRotate(avltree);break;
}
}```

## Right subtree rotation

Logical rotation with left subtree

code

```void ReBalanceAVLRightTree (struct Node **avltree) {
struct Node *R,*RL;
R = (*avltree)->rchild;switch(R->balancefactor){
case -1:
LeftSingleRotate(avltree);
break;
case 1:
RightSingleRotate(&(*avltree)->rchild);
LeftSingleRotate(avltree);
break;
case 0:
LeftSingleRotate(avltree);break;
}
}```

For the binary search tree, if the value stored in the node is equal to the search value, there is no need to add a node in the tree. If the value stored in the node is greater than the search value, the next search is carried out in the left subtree. If the value stored in the node is less than the search value, the next search is carried out in the right subtree.

Recursively find the location of the new node. Each time the new node is successful, it returns the insertion success, and tells the upper layer whether to modify the balance factor value of the upper layer.

For the position successfully added, because for the upper layer, the left / right node of the added position originally has no value, which is equivalent to that at least one of the left or right subtrees is empty. For upper nodes, the balance factor will inevitably change after adding nodes. Continuously transfer the change of balance factor upward.

At the same time, from the above discussion on the rotation of the left subtree, it can be seen that when the node increase leads to rebalancing, the height of the tree remains unchanged and the height does not increase. At the same time, the information that the height does not increase is passed to the parent node, represented by the variable grow th.

The code examples of the checks to be performed on the left subtree are as follows:

```switch((*avltree)->balancefactor){
case 1:
(*avltree)->balancefactor = 2;
ReBalanceAVLLeftTree(avltree);
*grow = false;
break;
case 0:
(*avltree)->balancefactor = 1;*grow = true;
break;
case -1:
(*avltree)->balancefactor = 0;*grow = false;
break;
}```

The code examples of the checks to be performed on the right subtree are as follows:

```switch((*avltree)->balancefactor){
case -1:
(*avltree)->balancefactor = -2;
ReBalanceAVLRightTree(avltree);
*grow = false;
break;
case 0:
(*avltree)->balancefactor = -1;*grow = true;
break;
case 1:
(*avltree)->balancefactor = 0;*grow = false;
break;
}```

The new node code is as follows:

```bool InsertEleIntoAVLTree(AVLNode **avltree,int insertkey,bool* grow){
if(*avltree == NULL){
New node of application space
}else{
if((*avltree)->data == insertkey){
*grow = false;
return false;
}else if ((*avltree)->data > insertkey){
bool success = InsertEleIntoAVLTree(&(*avltree)->lchild,insertkey,grow);
if(!success)
return false;
else if(*grow){
Change of balance factor of left subtree
}
}else{
bool success = InsertEleIntoAVLTree(&(*avltree)->rchild,insertkey,grow);
if(!success)
return false;
else if(*grow){
Change of balance factor of right subtree
}
}
}
return true;
}```

## Delete node

For the binary search tree, recursively find the location of the deleted node. If the node is deleted successfully, it returns the deletion success, and tells the upper layer whether it is necessary to modify the balance factor value of the upper layer, expressed by the variable degrow. Continuously transfer the change of balance factor upward.

From the above discussion on the rotation of the left subtree, it can be seen that when the node deletion leads to rebalancing, the height of the tree is bound to change, that is, the height is reduced, and the reduced height information is passed to the parent node.

Therefore, the balance factor changes due to the deletion of the left subtree node. The following checks should be performed:

```switch ((*avltree)->balancefactor)
{
case 1:
(*avltree)->balancefactor = 0;
break;
case 0:
(*avltree)->balancefactor = -1;
*degrow = false;
break;
case -1:
*degrow = true;
(*avltree)->balancefactor = -2;
ReBalanceAVLRightTree(avltree);
break;
}```

The following checks shall be performed for the change of balance factor caused by node division of the right subtree:

```switch ((*avltree)->balancefactor)
{
case -1:
(*avltree)->balancefactor = 0;
break;
case 0:
(*avltree)->balancefactor = 1;
*degrow = false;
break;
case 1:
*degrow = true;
(*avltree)->balancefactor = 2;
ReBalanceAVLLeftTree(avltree);
break;
}```

Deleting the node itself may require re linking the relationship between the node and the subtree, and the balance factor needs to be adjusted due to the change of the node, resulting in the change of the link between the node and the subtree

For the binary search tree, if the value stored in the node is equal to the search value, there is no need to add a node in the tree. If the value stored in the node is greater than the search value, the next search is carried out in the left subtree. If the value stored in the node is less than the search value, the next search is carried out in the right subtree.

(1) If the node to be deleted is found, there are left and right subtrees. Deleting will change the left and right subtrees

Suppose node a is the node to be deleted, l is the left subtree of a, and R is the right subtree of A. for a binary lookup tree, let the rightmost node in L subtree be LA. The value of LA can be greater than that of all nodes in L subtree and less than that of all nodes in R subtree. Therefore, node a can be replaced by LA, but if the LA node is deleted directly, It is difficult to determine whether the height of the l-subtree changes.

Consider the operation when adding A node. If you assign the value of La to node A, search the La node from the L subtree, find the LA, and then delete it. Note that in this process, the key value to be deleted at the beginning is A - > data, and the key value to be deleted later is La - > data, as shown in the above figure.

Set a variable realdel and initialize it to 1. When the value to be deleted is found, set the variable to 0, and then search the node to be deleted from the left subtree. Realdel has been set to 0 and will only change once. It will not reverse to 0. This process will only be executed once.

Code examples are as follows:

```if(*realdel == 1 && (*avltree)->lchild != NULL){
int realdata = FindRealDeleteEleValue(*avltree,*deletekey);
*deletekey = realdata;
(*avltree)->data = realdata;
*realdel = 0;
bool success = DeleteEleFromAVLTreeRecu(&(*avltree)->lchild,deletekey,degrow,realdel);
printf("Get %d\n");
if(!success)
return false;
else if(*degrow) {
*degrow = true;
The balance factor changes due to the deletion of the left subtree node. The following checks should be performed
}
}```

Code example of function FindRealDeleteEleValue

```int FindRealDeleteEleValue(BstNode *avltree,int key){
BstNode *L=avltree->lchild,*LR=L->rchild;
while(LR!=NULL){
L = LR;
LR = LR->rchild;
}
int data = L->data;
return data;
}```

(2) Delete to free up space

The code is as follows:

```BstNode *temp = *avltree;
if (*realdel == 0){
if((*avltree)->lchild == NULL){
*avltree = NULL;
}else{
*avltree = (*avltree)->lchild;
}
}else if((*avltree)->lchild == NULL){
*realdel = 0;
*avltree = (*avltree)->rchild;
}
free(temp);
*degrow = true;```

The complete code is as follows:

```#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

typedef struct Node{
int data;
int balancefactor;
struct Node *lchild,*rchild;
} AVLNode,BstNode;

void PreOrderTraverse(AVLNode * tree){
if(tree!=NULL){
printf("%d %d\n",tree->data,tree->balancefactor);
PreOrderTraverse(tree->lchild);
PreOrderTraverse(tree->rchild);
}
}

void InOrderTraverse(struct Node * tree){
if(tree!=NULL){
InOrderTraverse(tree->lchild);
printf("%d \n",tree->data);
InOrderTraverse(tree->rchild);
}
}

void RightSingleRotate(struct Node **avltree){
int leftbalancefactor =  (*avltree)->lchild->balancefactor,treebalancefactor=(*avltree)->balancefactor;
struct Node *temp = (*avltree)->lchild;
(*avltree)->lchild = temp->rchild;
temp->rchild = (*avltree);
*avltree = temp;

switch(treebalancefactor){
case 2:
switch(leftbalancefactor){
case 2 :
(*avltree)->balancefactor = 0;
(*avltree)->rchild->balancefactor = -1;
break;
case 1 :
(*avltree)->balancefactor = 0;
(*avltree)->rchild->balancefactor = 0;
break;
case 0 :
(*avltree)->balancefactor = -1;
(*avltree)->rchild->balancefactor = 1;
break;
}
break;
case 1:
switch(leftbalancefactor){
case 1 :
(*avltree)->balancefactor = -1;
(*avltree)->rchild->balancefactor = -1;
break;
case 0 :
(*avltree)->balancefactor = -1;
(*avltree)->rchild->balancefactor = 0;
break;
}
break;
}

}

void LeftSingleRotate(struct Node **avltree){
int rightbalancefactor =  (*avltree)->rchild->balancefactor,treebalancefactor=(*avltree)->balancefactor;
struct Node *temp = (*avltree)->rchild;
(*avltree)->rchild = temp->lchild;
temp->lchild = (*avltree);
*avltree = temp;

switch(treebalancefactor){
case -2:
switch(rightbalancefactor){
case -2 :
(*avltree)->balancefactor = 0;
(*avltree)->lchild->balancefactor = 1;
break;
case -1 :
(*avltree)->balancefactor = 0;
(*avltree)->lchild->balancefactor = 0;
break;
case 0 :
(*avltree)->balancefactor = 1;
(*avltree)->lchild->balancefactor = -1;
break;
}
break;
case -1:
switch(rightbalancefactor){
case -1 :
(*avltree)->balancefactor = 1;
(*avltree)->lchild->balancefactor = 1;
break;
case 0 :
(*avltree)->balancefactor = 1;
(*avltree)->lchild->balancefactor = 0;
break;
}
break;
}
}

void ReBalanceAVLRightTree (struct Node **avltree) {
struct Node *R,*RL;
R = (*avltree)->rchild;
switch(R->balancefactor){
case -1:
LeftSingleRotate(avltree);
break;
case 1:
RightSingleRotate(&(*avltree)->rchild);
LeftSingleRotate(avltree);
break;
case 0:
LeftSingleRotate(avltree);
break;
}
}

void ReBalanceAVLLeftTree(struct Node **avltree){
struct Node *L,*LR;
L = (*avltree)->lchild;
switch(L->balancefactor){
case 1:
RightSingleRotate(avltree);
break;
case -1:
LeftSingleRotate(&(*avltree)->lchild);
RightSingleRotate(avltree);
break;
case 0:
RightSingleRotate(avltree);
break;
}
}

int FindRealDeleteEleValue(BstNode *avltree,int key){
BstNode *L=avltree->lchild,*LR=L->rchild;
while(LR!=NULL){
L = LR;
LR = LR->rchild;
}
int data = L->data;
return data;
}

bool DeleteEleFromAVLTreeRecu(BstNode **avltree,int* deletekey , bool *degrow,int *realdel){
if(*avltree == NULL){
return false;
}else{
if((*avltree)->data == *deletekey){
if(*realdel == 1 && (*avltree)->lchild != NULL){
int realdata = FindRealDeleteEleValue(*avltree,*deletekey);
*deletekey = realdata;
(*avltree)->data = realdata;
*realdel = 0;
bool success = DeleteEleFromAVLTreeRecu(&(*avltree)->lchild,deletekey,degrow,realdel);
if(!success)
return false;
else if(*degrow) {
*degrow = true;
switch ((*avltree)->balancefactor)
{
case 1:
(*avltree)->balancefactor = 0;
break;
case 0:
(*avltree)->balancefactor = -1;
*degrow = false;
break;
case -1:
*degrow = true;
(*avltree)->balancefactor = -2;
ReBalanceAVLRightTree(avltree);
break;
}
}
}else {
BstNode *temp = *avltree;
if (*realdel == 0){
if((*avltree)->lchild == NULL){
*avltree = NULL;
}else{
*avltree = (*avltree)->lchild;
}
}else if((*avltree)->lchild == NULL){
*realdel = 0;
*avltree = (*avltree)->rchild;
}
free(temp);
*degrow = true;
}
}else if ((*avltree)->data > *deletekey){
bool sucess = DeleteEleFromAVLTreeRecu(&(*avltree)->lchild,deletekey,degrow,realdel);
if(!sucess)
return false;
else if(*degrow){
*degrow = true;
switch ((*avltree)->balancefactor)
{
case 1:
(*avltree)->balancefactor = 0;
break;
case 0:
(*avltree)->balancefactor = -1;
*degrow = true;
break;
case -1:
*degrow = true;
(*avltree)->balancefactor = -2;
ReBalanceAVLRightTree(avltree);
break;
}
}
}else{
bool sucess = DeleteEleFromAVLTreeRecu(&(*avltree)->rchild,deletekey,degrow,realdel);
if(!sucess)
return false;
else if(*degrow){
*degrow = true;
switch ((*avltree)->balancefactor)
{
case -1:
(*avltree)->balancefactor = 0;
break;
case 0:
(*avltree)->balancefactor = 1;
*degrow = true;
break;
case 1:
*degrow = true;
(*avltree)->balancefactor = 2;
ReBalanceAVLLeftTree(avltree);
break;
}
}
}
}
return true;
}

bool DeleteEleFromAVLTree(BstNode **avltree,int deletekey ){
int realdevalue = 1;
int *realdel = &realdevalue;
int delkey = deletekey;
bool degrow = false;
return DeleteEleFromAVLTreeRecu(avltree , &delkey,&degrow,realdel);
}

bool InsertEleIntoAVLTree(AVLNode **avltree,int insertkey,bool* grow){
if(*avltree == NULL){
*avltree = (AVLNode *)malloc(sizeof(AVLNode));
(*avltree)->data = insertkey;
(*avltree)->lchild = (*avltree)->rchild = NULL;
(*avltree)->balancefactor = 0;
*grow = true;
}else{
if((*avltree)->data == insertkey){
*grow = false;
return false;
}else if ((*avltree)->data > insertkey){
bool success = InsertEleIntoAVLTree(&(*avltree)->lchild,insertkey,grow);
if(!success)
return false;
else if(*grow){
switch((*avltree)->balancefactor){
case 1:
(*avltree)->balancefactor = 2;
ReBalanceAVLLeftTree(avltree);
*grow = false;
break;
case 0:
(*avltree)->balancefactor = 1;*grow = true;
break;
case -1:
(*avltree)->balancefactor = 0;*grow = false;
break;
}
}
}else{
bool success = InsertEleIntoAVLTree(&(*avltree)->rchild,insertkey,grow);
if(!success)
return false;
else if(*grow){
switch((*avltree)->balancefactor){
case -1:
(*avltree)->balancefactor = -2;
ReBalanceAVLRightTree(avltree);
*grow = false;
break;
case 0:
(*avltree)->balancefactor = -1;*grow = true;
break;
case 1:
(*avltree)->balancefactor = 0;*grow = false;
break;
}
}
}
}
return true;
}

int main(void){
AVLNode * tree=NULL;
int arr[] = {22,11,10,5,2,24,25,23,35,10};
int index = 0;
for(index = 0 ; index < 9 ; ++index){
bool flag;
printf("Input data : %d\n",arr[index]);
if(InsertEleIntoAVLTree(&tree, arr[index],&flag)){
printf("#########################\n");
printf("PreOrderTraverse start!\n");
PreOrderTraverse(tree);
printf("PreOrderTraverse stop!\n");
printf("#########################\n");
printf("InOrderTraverse start!\n");
InOrderTraverse(tree);
printf("InOrderTraverse stop!\n");
printf("#########################\n");
}
}

int arr2[] = {23,35,2,5,22,10,22,24,25,11,5,2};
for(index = 0 ; index < 10 ; ++index){
bool flag;
printf("Delete data : %d\n",arr2[index]);
flag = DeleteEleFromAVLTree(&tree, arr2[index]);
if (flag){
printf("#########################\n");
printf("PreOrderTraverse start!\n");
PreOrderTraverse(tree);
printf("PreOrderTraverse stop!\n");
printf("#########################\n");
printf("InOrderTraverse start!\n");
InOrderTraverse(tree);
printf("InOrderTraverse stop!\n");
printf("#########################\n");
}
else{
printf("Can't find the key!\n");
}
}

return 0;
}
```

Posted on Sat, 04 Dec 2021 17:10:27 -0500 by toyartist