1

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.

  • 1
    I notice the function `node_t* find_parent()` recurses without making use of its return value. For example `else find_parent(value, start->left);`. Should it be `else return find_parent(...);` etc? – Weather Vane Jun 23 '19 at 19:10
  • You may fine [AVL Tree in C (Martin Broadhurst)](http://www.martinbroadhurst.com/avl-tree-in-c.html) very useful. – David C. Rankin Jun 23 '19 at 19:59
  • @ David my problem was way more specific than that but thanks. @ Weather Vane that actually was it, thanks. – Nelson Mongare Jun 23 '19 at 20:18

0 Answers0