Whenever the number of nodes in the AVL pass 8 nodes and the algorithm tries to re-balance, on inserting the 9th node, most of the nodes in the tree are lost
I implemented an AVL tree in c and the insert function checks the trees balance after every insert. The check balance function tries to re-balance the tree when called (if necessary) and it does this by rotating (as is standard for AVL trees), either by left rotating or right rotating or a combination of both. However whenever the number of nodes exceeds 8(this is probably arbitrary though) some of the nodes are lost. After every rotation the parent of the previous root of the sub-tree is found and it's left or right pointer is changed accordingly eg: if I have a tree like
97 97
/ /
96 95
/ Right / \
95 ====> 94 96
/ Rotate on 96
94
96 was the previous parent of the sub-tree but it's 95 after rotating therefore 97s "left" pointer has to change from 96 to 95.
So the insert process is: place value => check balance => rotate(if necessary)
place value function:
void place_value(node_t* root, node_t* in) {
if(root->val > in->val) {
if(root->left == NULL)
root->left = in;
else
place_value(root->left, in);
}
else if(root->val < in->val) {
if(root->right == NULL)
root->right = in;
else
place_value(root->right, in);
} else {
/*kill the node*/
}
if(check_balance(root) == 1) {
fflush(stdout);
}
}
check balance function:
int check_balance(node_t* root) {
int flag = 0;
if((height(root->left, 0)- height(root->right, 0))>1) {
if((height(root->left->left, 0)- height(root->left->right, 0))>0) {
right_rotate(root);
flag = 1;
} else {
left_right(root);
flag = 1;
}
}
if((height(root->left, 0)- height(root->right, 0))<-1) {
if((height(root->right->left, 0)- height(root->right->right, 0))<0) {
left_rotate(root);
flag = 1;
} else {
right_left(root);
flag = 1;
}
}
return flag;
}
the left and right rotate more or less follow the same template:
void left_rotate(node_t* root) {
if(root == NULL || root->right == NULL)
return;
node_t* parent = find_parent(root->val, root->bst_l->Head);
node_t* right_node = root->right;
root->right = right_node->left;
right_node->left = root;
if(parent == NULL) {
root->bst_l->Head = right_node;
return;
}
if(root->val > parent->val)
parent->right = right_node;
else
parent->left = right_node;
}
An example of a combined rotation:
void left_right(node_t* root) {
left_rotate(root->left);
right_rotate(root);
}
So I did a pre-order traversal of the BST after every insert and this is what tree looked like:
100
100 99
99 98 100
98 97 99 100
98 97 96 99 100
98 96 95 97 99 100
96 95 94 99 98 97 100
98 96 94 93 95 97 99 100
94 96 97
Inserting 92 broke the tree and lost some data
before the data is lost, the preorder traversal shows that the tree looks like this:
98
/ \
96 99
/ \ \
94 97 100
/ \
93 95
which is balanced. After inserting 92 I expect the tree to look like this:
---98---
/ \
95 99
/ \ \
93 96 100
/ \ \
92 94 97
But instead it looks like:
94
\
96
\
97
Initially I though it was because the OS was arbitrarily cleaning up memory that it though wasn't being used, but that doesn't make sense cause the process that owns the memory is still running. Other possible causes of breaks are:
The find parent function:
node_t* find_parent(int value, node_t* start) {
int val = value;
if(start == NULL)
return NULL;
if(val == start->val)
return NULL;
if(val < start->val) {
if(start->left == NULL)
return NULL;
else if(start->left->val == val)
return start;
else
find_parent(value, start->left);
} else if(val > start->val){
if(start->right == NULL)
return NULL;
else if(start->right->val == val)
return start;
else
find_parent(value, start->right);
} else { }
return NULL;
}
I tried to step through the code but couldn't pin point EXACTLY what was causing the issue, though I did discover that the BST breaks when the algo attempts a left-right rotation on 96 with the BST in this state:
98
/ \
96 99
/ \ \
94 97 100
/ \
93 95
when inputting 92.