Почему мои функции баланса AVL теряют данные? - PullRequest
1 голос
/ 23 июня 2019

Всякий раз, когда число узлов в AVL проходит 8 узлов, и алгоритм пытается перебалансировать, при вставке 9-го узла большинство узлов в дереве теряются

Я реализовал дерево AVL в c, и функция вставки проверяет баланс деревьев после каждой вставки. Функция контрольного баланса пытается перебалансировать дерево при вызове (при необходимости) и делает это вращением (как стандартно для деревьев AVL), либо вращением влево, либо вращением вправо, либо комбинацией обоих. Однако всякий раз, когда количество узлов превышает 8 (хотя это, вероятно, произвольно), некоторые из узлов теряются. После каждого поворота обнаруживается родитель предыдущего корня поддерева, и его левый или правый указатель соответственно изменяются, например: если у меня есть дерево, подобное

        97                                        97                 
       /                                          /
     96                                         95
    /          Right                           /  \
   95          ====>                         94    96
  /            Rotate on 96
 94    

96 был предыдущим родителем поддерева, но после поворота он равен 95, поэтому «левый» указатель 97 с должен измениться с 96 на 95.

Итак, процесс вставки: значение места => проверить баланс => повернуть (при необходимости)

функция значения места:

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);
    }
}

функция проверки баланса:

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;

}

левый и правый поворот более или менее следуют одному и тому же шаблону:

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;
}

Пример комбинированного вращения:

void left_right(node_t* root) {
    left_rotate(root->left);
    right_rotate(root);
}

Итак, я делал предварительный обход BST после каждой вставки, и вот как выглядело это дерево:

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  

Вставка 92 сломала дерево и потеряла некоторые данные

перед потерей данных, обход предзаказа показывает, что дерево выглядит так:

                         98
                        /  \
                      96    99
                     /  \    \
                   94    97  100
                  /  \
                93    95

, который сбалансирован. После вставки 92 я ожидаю, что дерево будет выглядеть так:

                         ---98---
                        /        \
                      95         99
                     /  \          \
                   93    96        100
                  /  \     \
                92    94    97

Но вместо этого это выглядит так:

                         94
                           \
                            96
                              \
                              97

Сначала я думал, что операционная система произвольно очищала память, хотя она и не использовалась, но это не имеет смысла, потому что процесс, которому принадлежит память, все еще выполняется. Другие возможные причины перерывов:

Функция поиска родительского элемента:

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;
}

Я попытался пошагово пройти по коду, но не смог точно указать, что именно вызвало проблему, хотя я обнаружил, что BST обрывается, когда алгоритм пытается повернуть налево-направо на 96 с BST в этом состоянии:

                         98
                        /  \
                      96    99
                     /  \    \
                   94    97  100
                  /  \
                93    95

при вводе 92.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...