简体   繁体   English

叶子删除后如何重新平衡AVL树?

[英]How to rebalance AVL tree after leaf deletion?

Here is how I think it should be done (after reading p. 652 of DS Malik's "Data Structures using C++" 2nd). 我认为应该这样做(在阅读了DS Malik的“使用C ++的数据结构”第二页的第652页之后)。 We traverse the path leading to the deleted leaf starting from its parent. 我们从父级开始遍历通向删除叶子的路径。 For every node P along this path we do what is presented below. 对于沿着此路径的每个节点P ,我们执行以下操作。 Suppoose the deletion has shorted the shorter subtree of P and Q is the root of the taller subtree of P . Suppoose删除已短路的短子树PQ是的较高子树的根P Let bf() denote balance_factor. bf()表示balance_factor。

  1. if |bf(P)|>1 and bf(Q) = 0 , then rotate P 如果|bf(P)|>1bf(Q) = 0 ,则旋转P

  2. if |bf(P)|>1 and bf(Q) has the same sign as bf(P) , then rotate P 如果|bf(P)|>1bf(Q)具有相同的符号如bf(P)然后转动P

  3. if |bf(P)|>1 and bf(Q) has opposite sign to bf(P) , then first rotate Q , then rotate P (even if after Q 's rotation bf(P) = 0 ) 如果|bf(P)|>1并且bf(Q)bf(P) bf(Q)具有相反的符号,则首先旋转Q ,然后旋转P (即使在Q旋转bf(P) = 0

  4. if |bf(P)|<2 , then do nothing with P and proceed to P 's parent 如果|bf(P)|<2 ,则对P不执行任何操作并转到P的父级

Is this correct? 这个对吗?

The algorithm looks good. 该算法看起来不错。 I have tested it many times with the help of the C++ program below. 我已经在下面的C ++程序的帮助下对其进行了多次测试。 Function Tree::remove() deletes a node and function Tree::rebalance_del() rebalances the tree after deletion. 函数Tree::remove()删除节点,函数Tree::rebalance_del()在删除后重新平衡树。 In this program the deletion of any node is reduced to the deletion of one-child/leaf node (through copying the content of the node into its immediate predecessor). 在此程序中,任何节点的删除都减少为一个子节点/叶子节点的删除(通过将节点的内容复制到其直接的前任节点中)。 The program uses graphviz for tree visualisation and works in Linux. 该程序使用graphviz进行树可视化,并在Linux中工作。

#include<iostream>
#include<cstdlib>
#include<deque>
#include<vector>
#include<iterator>
#include<fstream>
#include<algorithm>
#include<set>

using namespace std;

template <typename elemType> 
class Tree;

template <typename elemType> 
class Node{
    friend class Tree<elemType>;
public:
    Node(elemType val): _val(val), _lchild(0), _rchild(0){ }
    elemType val() const { return _val; }
    elemType &val(){ return _val; }
    Node *lchild() const { return _lchild;}
    Node *&lchild() { return _lchild;}
    Node *rchild() const { return _rchild;}
    Node *&rchild() { return _rchild;}
    void insert(Node *temp);
    void graph(string filename);
    Node *find(elemType val);
    Node *find_parent(elemType val);
private:
    elemType _val;
    Node *_lchild;      
    Node *_rchild;
};

template <typename elemType>
class Tree{
public:
    Tree(): _root(0){}
    Tree(elemType *start, elemType *end);
    void insert(elemType val);
    int height(Node<elemType> *node);
    int balance_factor(Node<elemType> *node);
    bool rotate(Node<elemType> *parent, Node<elemType> *child);
    bool rotate_root();
    Node<elemType> *root(){ return _root;}
    void graph(string filename);
    Node<elemType> * find(elemType val);
    Node<elemType> * find_parent(elemType val);
    Node<elemType> * find_predsor(Node<elemType> *node);
    void remove(elemType val);
    void rebalance_del(Node<elemType> *node);
    void rotate_right(Node<elemType> *parent, Node<elemType> *node);
    void rotate_left(Node<elemType> *parent, Node<elemType> *node);
private:
    Node<elemType> *_root;  
};

template <typename elemType>
void Node<elemType>::insert(Node *temp)
{
        if (_val > temp->val() )
        {
            if (_lchild)
                _lchild->insert(temp);
            else
            {
                _lchild = temp;
            }
        }
        else
        {
            if (_rchild)
                _rchild->insert(temp);
            else
            {
                _rchild = temp;
            }
        }
}

template <typename elemType>
void Node<elemType>::graph(string filename)
{
        ofstream out_file(filename.c_str(),ios_base::app);

        if (_lchild)
        {
            out_file << _val << "->" << _lchild->val() << ";" << endl;
            _lchild->graph(filename);
        }
        if (_rchild)
        {
            out_file << _val << "->" << _rchild->val() << ";" << endl;
            _rchild->graph(filename);
        }
}

template <typename elemType>
Node<elemType> *Node<elemType>::find(elemType val)
{
        if (_val == val)
                return this;
        else if (_val > val)
        {
                if (_lchild)
                    return _lchild->find(val);
        }
        else
        {
                if (_rchild)
                    return _rchild->find(val);
        }
        return 0;           
}

template <typename elemType>
Node<elemType> *Node<elemType>::find_parent(elemType val)
{
        if ( (_lchild && _lchild->val() == val) || (_rchild && _rchild->val() == val) )
                return this;
        else if (_val > val)
        {
                if (_lchild)
                    return _lchild->find_parent(val);
        }
        else
        {
                if (_rchild)
                    return _rchild->find_parent(val);
        }
        return 0;       
}   

template <typename elemType>
Tree<elemType>::Tree(elemType *start, elemType *end): _root(0)
{
        while(start != end)
        {
            insert(*start);
            ++start;        
        }
} 

template <typename elemType>
void Tree<elemType>::insert(elemType val)
{
        Node<elemType> *temp = new Node<elemType>(val);
        if (!_root)
        {
            _root = temp;
            return;
        }
        else
            _root->insert(temp);    

        Node<elemType> *child = find_parent(val); 
        while (child != _root)
        {       
            Node<elemType> *parent = find_parent(child->val());
            rotate(parent, child);
            child = parent; 
        }
        rotate_root();
}

template <typename elemType>
int Tree<elemType>::height(Node<elemType> *node)
{
        if (!node)
                return 0;

        return max( height(node->lchild()), height(node->rchild()) ) + 1;       
}

template <typename elemType>
int Tree<elemType>::balance_factor(Node<elemType> *node)
{
        if (!node)
                return 0;
        return height( node->rchild() ) - height( node->lchild() );     
}

template <typename elemType>
bool Tree<elemType>::rotate(Node<elemType> *parent, Node<elemType> *child)
{
        if (!parent || !child)
            return false;

        bool to_right;
        int bf = balance_factor(child);
        if (bf < -1 )
            to_right = true;
        else if (bf > 1 )
            to_right = false;
        else
            return false;       

        if(to_right)
        {
                Node<elemType> *gchild = child->lchild();
                if ( balance_factor (gchild) > 0 )
                        rotate_left(child,gchild);

                rotate_right(parent,child);
        }
        else
        {
                Node<elemType> *gchild = child->rchild();
                if ( balance_factor (gchild) < 0 )
                        rotate_right(child,gchild);

                rotate_left(parent,child);
        }
}

template <typename elemType>
bool Tree<elemType>::rotate_root()
{
        if (!_root)
            return false;

        bool to_right;
        int bf = balance_factor(_root);
        if (bf < -1 )
            to_right = true;
        else if ( bf > 1 )
            to_right = false;
        else
            return false;       

        if(to_right)
                rotate_right(0,_root);
        else
                rotate_left(0,_root);

        return true;
}

template <typename elemType>
void Tree<elemType>::graph(string filename)
{
        ofstream out_file(filename.c_str(),ios_base::out);
        out_file << "digraph G{\n graph [ordering=\"out\"];" << endl;
        out_file.close();
        if (!_root)
            return;
        _root->graph(filename);
        out_file.open(filename.c_str(),ios_base::app);
        out_file << "}";                
}


template <typename elemType>
Node<elemType> * Tree<elemType>::find(elemType val)
{
        if (!_root)
            return 0;
        return _root->find(val);                
}

template <typename elemType>
Node<elemType> * Tree<elemType>::find_parent(elemType val)
{
        if (!_root)
            return 0;
        return _root->find_parent(val);             
}

template <typename elemType>
Node<elemType> *Tree<elemType>::find_predsor(Node<elemType> *node)
{
        if (!node || !node->lchild())
            return 0;

        Node<elemType> *temp = node->lchild();
        while(temp && temp->rchild())
                temp = temp->rchild();

        return temp;    
}

template <typename elemType>
void Tree<elemType>::remove(elemType val)
{
        if (!_root)
            return;

        Node<elemType> *to_remove;
        if ( ! (to_remove = find(val)) )
        {
                cout << val << " is not present" << endl;
                return;
        }

        Node<elemType> *node = find_parent(val); 
        Node<elemType> *predsor = find_predsor(to_remove);

        if ( to_remove->lchild() && to_remove->rchild() )
        {
                node = find_parent(predsor->val());
                elemType temp = to_remove->val();
                to_remove->val() = predsor->val();
                predsor->val() = temp;
                to_remove = predsor;
        }

        if ( node->rchild() == to_remove )
                if (to_remove->lchild())
                        node->rchild() = to_remove->lchild();
                else
                        node->rchild() = 0;
        else
                if (to_remove->lchild())
                        node->lchild() = to_remove->lchild();
                else
                        node->lchild() = 0;

        delete to_remove;
        cout << "Node " << val << " was removed" << endl;

        rebalance_del(node);
}

template <typename elemType>
void Tree<elemType>::rebalance_del(Node<elemType> *node)
{   
        while (node)
        {       
            Node<elemType> *parent = find_parent(node->val());

            int bfp = balance_factor(node);
            if (bfp > 1)
            {
                int bfq = balance_factor(node->rchild());
                if (bfq > -1)
                        rotate_left(parent,node);
                else
                {
                        rotate_right(node,node->rchild());
                        rotate_left(parent,node);
                }
            }
            else if (bfp < -1)
            {
                int bfq = balance_factor(node->lchild());
                if (bfq < 1)
                        rotate_right(parent,node);
                else
                {
                        rotate_left(node,node->lchild());
                        rotate_right(parent,node);
                }
            }
            node = parent; 
        }
}

template <typename elemType>
void Tree<elemType>::rotate_right(Node<elemType> *parent, Node<elemType> *node)
{
        if (!node)
                return; 

        Node<elemType> *temp = 0;

        if( node->_lchild)
        {
                temp = node->_lchild->_rchild;
                node->_lchild->_rchild = node;
        }
        node = node->_lchild;
        if (node && node->_rchild)
        {
                node->_rchild->_lchild =  temp;
        }
        if (parent)
        {
                if (node && parent->_rchild == node->_rchild)
                        parent->_rchild = node;
                else if (node && parent->_lchild == node->_rchild)      
                        parent->_lchild = node;
                else;       
        }
        else
            _root = node;
}

template <typename elemType>
void Tree<elemType>::rotate_left(Node<elemType> *parent, Node<elemType> *node)
{
        if (!node)
                return; 

        Node<elemType> *temp = 0;

        if( node->_rchild)
        {
                temp = node->_rchild->_lchild;
                node->_rchild->_lchild = node;
        }
        node = node->_rchild;
        if (node && node->_lchild)
        {
                node->_lchild->_rchild =  temp;
        }
        if (parent)
        {
                if (node && parent->_lchild == node->_lchild)
                        parent->_lchild = node;
                else if (node && parent->_rchild == node->_lchild)      
                        parent->_rchild = node;
                else;       
        }
        else
            _root = node;
}


int main(int argc,char *argv[])
{
    typedef int elemType;
    set<elemType> elems;
    srand(time(NULL));
    Tree<elemType> tree;

    //tree generation
    ofstream out_file("tree.dat");
    for (int ix = 0; ix < 10000; ++ix)
    {
        elemType val = rand() % 100;
        if (elems.count(val))
            continue;   
        tree.insert( val ); 
        out_file << val << ' ';
        elems.insert(val);
    }

    //print tree to file
    tree.graph("tree_before.dot");
    system("dot -Tpng tree_before.dot > tree_before.png");

    //delete node with to_del key
    int to_del = 33;
    tree.remove(to_del);

    //print rebalanced tree without node to_del
    tree.graph("tree_after.dot");
    system("dot -Tpng tree_after.dot > tree_after.png");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM