Anderson tree problem

Anderson tree problem

本文关键字:problem tree Anderson      更新时间:2023-10-16

我想用Anderson树来做一些事情。因此,我开始将Julienne Walker版本移植到C++:http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_andersson.aspx

现在我有插入工作。但问题是,如果我使用优化编译,它会崩溃。甚至-O1也崩溃了。

template <class Tv>
class AaTree
{
private:
    template <typename Tdata>
    struct AaNode
    {
        AaNode()
        {
            level = 0;
            link[0] = 0L;
            link[1] = 0L;
        }
        ~AaNode()
        {}

        int level;
        Tdata data;
        AaNode<Tdata>* link[2];
    };

    AaNode<Tv>* root;
    AaNode<Tv>* nil;  // sentinel
    inline AaNode<Tv>* make_node(Tv data, int level)
    {
        AaNode<Tv>* rn = new AaNode<Tv>();
        rn->data = data;
        rn->level = level;
        rn->link[0] = rn->link[1] = nil;
    }
    inline AaNode<Tv>* skew(AaNode<Tv>* t)
    {
        if (t->link[0]->level == t->level && t->level != 0)
        {
            AaNode<Tv>* save = t->link[0];
            t->link[0] = save->link[1];
            save->link[1] = t;
            t = save;
        }
        return t;
    }

    inline AaNode<Tv>* split(AaNode<Tv>* t)
    {
        if (t->link[1]->link[1]->level == t->level && t->level != 0)
        {
            AaNode<Tv>*save = t->link[1];
            t->link[1] = save->link[0];
            save->link[0] = t;
            t = save;
            ++t->level;
        }
        return t;
    }

    AaNode<Tv>* _insert(AaNode<Tv>* root, Tv data)
    {
        if (root == nil)
            root = make_node(data, 1);
        else {
            AaNode<Tv>* it = root;
            AaNode<Tv>* path[64];
            int top=0, dir=0;
            for (;;) 
            {
                path[top++] = it;
                dir = it->data < data;
                if (it->link[dir] == nil)
                    break;
                it = it->link[dir];
            }
            it->link[dir] = make_node(data, 1);
            while (--top >= 0) 
            {
                if (top != 0)
                    dir = path[top - 1]->link[1] == path[top];
                path[top] = skew(path[top]);
                path[top] = split(path[top]);
                    if ( top != 0 )
                    path[top - 1]->link[dir] = path[top];
                else
                    root = path[top];
            }
        }
        return root;
    }       
    void _print(AaNode<Tv>* root)
    {
        if (root != nil)
        {
            _print(root->link[0]);
            printf("level(%d): %dn", root->level, root->data);
            _print(root->link[1]);
        }
    }

public:
    AaTree()
        : root(0L)
    {
        nil = new AaNode<Tv>();
        root = nil;
    }
    ~AaTree()
    {}
    void Insert(Tv data)
    {
        root = _insert(root, data);
    }
    void Delete(Tv data)
    {
        root = _remove(root, data);
    }
    void Print()
    {
        _print(root);
    }   
};

int main(int argc, char* argv[])
{
    AaTree<int> tree;
    for (int i = 0; i < 100; i++)
        tree.Insert(i);
    tree.Print();
    return 0;
}

您的make_node函数声称返回一个值,但不包含返回语句。

struct AaNode在您的案例中不应该是模板。尝试删除它,看看会发生什么。

struct AaNode
    {
        AaNode()
        {
            level = 0;
            link[0] = 0L;
            link[1] = 0L;
        }
        ~AaNode()
        {}

        int level;
        Tv  data;
        AaNode* link[2];
    };

但在任何情况下,make_node((都必须返回一个值。我甚至不知道你是怎么编译的。

  1. 使用正确的构造初始值设定项列表:

    AaNode()
    :
        level(0),
        data(),
        link()
    {
        link[0] = 0L;
        link[1] = 0L;
    }
    
  2. 从函数中删除内联关键字。内联应该保留给非常小的函数(一般原则是最多一到两行(,您试图内联的函数太大,很可能比正常调用效率更高。

  3. 您的基本值nil可能应该是const static。此外,用一些容易识别的值初始化它也不会有什么坏处,这可能有助于调试。

  4. 在slaw((和split((中,在取消引用指针之前,您没有进行任何检查以确保t有效或t的链接有效。

  5. 正如其他人所指出的,make_node不会返回它创建的节点。

  6. insert中,你的for循环不会检查以确保它没有访问越界内存(>路径的第64个条目(