Удаление в дереве AVL

Поскольку вы знаете, как должен быть сбалансирован avl после удаления узла, я перейду к делу. Для начала я подумываю об удалении узла без дочерних элементов.

Например, дерево:

        10
      /     \
     5      17
   /  \    /  \ 
   2  9   12  20
    \           \
     3          50

Допустим, deletevalue (12);

Тогда Дерево после удаления должно быть:

        10
      /     \
     5      17
   /  \       \ 
   2  9       20
    \           \
     3          50

Теперь мы видим, что дерево сбалансировано в узле 17, потому что по формуле его коэффициент баланса = высота (левое поддерево [левое дерево имеет нулевое значение, поэтому -1]) - высота (правое поддерево) = -2

Итак, мы уравновешиваем дерево, проверяя его регистр справа-справа или справа-слева.

If BalanceFactor(17's right) = -1
    perform SingleLeftRotation(17);
else if BalanceFactor(17's right) = -1
    perform DoubleRightLeftRotation(17);

То же самое и в случае, если коэффициент баланса 17 равен 2, то есть он оставлен на высоком уровне, тогда его соответствующие вращения. // для bF (17) = 2

If BalanceFactor(17's left) = 1
    perform SingleLeftRotation(17);
else if BalanceFactor(17's left) = -1
    perform DoubleLeftRightRotation(17);

После балансировки дерево должно стать таким:

          10
      /     \
     5      20
   /  \    /  \ 
   2  9   17  50
    \           
     3  

Это удаление, которое я разработал.

Из основной функции я вызываю

bool deletevalue(WA value)
{
    AvLNode<WA> *temp = search(root, value);    //calling search function to find node which has user-specified data & stored its address in temp pointer
    if(temp!=0) //if temp node is not null then
    {
        if(temp->left==0 && temp->right==0) //if temp node don't have any children
        {   deletewithNochild(root, value); }   //call to respective function
        else if( (temp->left!=0 && temp->right==0) || (temp->left==0 && temp->right!=0) )   //if temp node has any 1 child, left or right
        {   deletewithOneChild(temp);   }   //call to respective function
        else if(temp->left!=0 && temp->right!=0)    //if temp node has 2 children
        {   deletewith2Child(temp);     }   //call to respective function

        return true;    //for prompting respective output message
    }
    else
        return false;   //for prompting respective output message
}

поскольку наш требуемый узел не имеет дочернего элемента, вызывается следующая функция.

void deletewithNochild(AvLNode<WA> *temp, WA value) //temp is node which is to be deleted
{
    if(value == root->key)  //if temp is root node then
    {
        delete root;    //free memory of root node
        root = 0;   //nullify root
    }
    else    //if temp is some other node 
    {
        if (value < temp->key)
        {
            deletewithNochild(temp->left, value);
        }
        else if (value > temp->key)
        {
            deletewithNochild(temp->right, value);
        }
        else if (value == temp->key)
        {
            AvLNode<WA> *father = findfather(temp, root);   //calling findfather func to find father of temp node & store its address in father node pointer

            if(father->left==temp)  //if temp is left child of its father
            {
                delete temp;    //free memory of temp node
                father->left=0; //nullify father's left
            }
            else if(father->right==temp)    //if temp is right child of its father
            {
                delete temp;    //free memory of temp node
                father->right=0;//nullify father's right
            }
            return;
        }
        cout<<"\nBalancing";
        if ( balancefactor(temp) == 2)  //if temp is left higher, ie. temp's Balance Factor = 2, then
        {
            cout<<"\t2 ";
            if ( balancefactor(temp->left) == 1 ) //if temp's left node has Balance Factor 1 then
            {
                SingleRightRotation(temp);  //send temp node for rotation because temp is unbalance
            }
            else if ( balancefactor(temp->left) == -1 ) //if temp's left node has Balance Factor -1, then
            {
                DoubleLeftRightRotation(temp);  //send temp for double rotation because temp is unbalance
            }
        }
        else if ( balancefactor(temp) == -2 )   //if temp is right higher, ie. temp's Balance Factor = -2, then
        {
            cout<<"\t-2 ";
            if ( balancefactor(temp->right) == -1 ) //if temp's left node has Balance Factor -1 then
            {
                SingleLeftRotation(temp);   //send temp node for rotation because temp is unbalance
            }
            else if ( balancefactor(temp->right) == 1 ) //if temp's right node has Balance Factor 1, then
            {
                DoubleRightLeftRotation(temp);  //send temp for double rotation because temp is unbalance
            }
        }

    }
}

Вот две полезные функции: ВЫСОТА узла и КОЭФФИЦИЕНТ БАЛАНСА узла.

int heightofnode(AvLNode<WA> *temp) const
{
    return temp==NULL ? -1 : temp->height;
}


int balancefactor(AvLNode<WA> *temp) const
{
    return ( heightofnode(temp->left) - heightofnode(temp->right) );
}

Мои выходные данные, когда я удаляю 12, становятся (Первые обходы в ширину) - >> [10] [9] [17]

Пожалуйста, помогите мне, есть ли проблемы с рекурсией? Я снова и снова пробежался всухую, но не могу понять. Удаление должно производиться через рекурсию, иначе дерево балансировки было бы большим адом. Заранее благодарим за уделенное время. :-)


person InamTaj    schedule 11.12.2012    source источник


Ответы (1)


Почему deletewithNochild () вызывает любые другие методы delete *? Если вызывается deletewithNochild, вы находитесь на удаляемом узле. Просто удалите его, перейдите к его родительскому элементу, проверьте коэффициент баланса родителей и при необходимости измените его. Повторите перебалансировку для каждого родительского узла, пока не дойдете до корня.

Если это поможет, я реализовал дерево AVL в Java, если вам нужна ссылка.

person Justin    schedule 12.12.2012
comment
Я думаю, вы не рассмотрели deletewitnNochild () подробно. Его рекурсивная функция. Вот что происходит. (значение = значение, которое нужно удалить) 1. Если значение находится в корне, удалить корень и обнулить корень, поскольку у него нет дочерних элементов. 2. Если значение меньше корня, перейдите в левое поддерево, чтобы найти узел со значением. 3. Если значение больше корня, перейдите в правое поддерево, чтобы найти узел со значением. 4. Когда он будет найден, удалите его и вернитесь к предыдущему вызову (Отец удаленного узла) 5. Проверьте дисбаланс и поверните по мере необходимости. 6. Вернитесь к предыдущему вызову. 7. И так, пока не дойдем до root. - person InamTaj; 12.12.2012