【问题标题】:What wrong with my Red Black Tree destructor?我的红黑树析构函数出了什么问题?
【发布时间】:2013-03-04 08:33:03
【问题描述】:

我正在构建一棵红黑树,但我的类 RBTree 的析构函数可能存在一些问题。我将 10^7 值添加到树中,然后调用析构函数,但内存似乎没有被释放。 (我查看了系统监视器,我的程序仍然使用 200MB)。

你能告诉我我的析构函数出了什么问题吗?这是我的源代码。

对不起,我的英语不好。

#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;

enum Color {RED, BLACK};

template<class Data> class RBNode;
template<class Data> class RBTree;

template<class Data> class RBNode {
    Color color; RBNode *p, *left, *right;
public:
    Data v;
    RBNode(Color color, RBNode *p, RBNode *left, RBNode *right, Data v):
        color(color), p(p), left(left), right(right), v(v) {}
    RBNode() {}
    friend class RBTree<Data>;
};

template<class Data> class RBTree {
    typedef RBNode<Data> Node;
    typedef Node * PNode;
    PNode root, nil;

    void LeftRotate(PNode x) {
        PNode y = x->right; x->right = y->left;
        if(y->left != nil) y->left->p = x;
        y->p = x->p;
        if(x->p == nil) root = y;
        else if(x == x->p->left) x->p->left = y;
        else x->p->right = y;
        y->left = x; x->p = y;
    }

    void RightRotate(PNode y) {
        PNode x = y->left; y->left = x->right;
        if(x->right != nil) x->right->p = y;
        x->p = y->p;
        if(y->p == nil) root = x;
        else if(y == y->p->left) y->p->left = x;
        else y->p->right = x;
        x->right = y; y->p = x;
    }

    void insertFixUp(PNode z) {
        while(z->p->color == RED) {
            if(z->p == z->p->p->left) {
                PNode y = z->p->p->right;
                if(y->color == RED) z->p->color = y->color = BLACK, z->p->p->color = RED, z = z->p->p;
                else {
                    if(z == z->p->right) LeftRotate(z = z->p);
                    z->p->color = BLACK; z->p->p->color = RED; RightRotate(z->p->p);
                }
            } else {
                PNode y = z->p->p->left;
                if(y->color == RED) z->p->color = y->color = BLACK, z->p->p->color = RED, z = z->p->p;
                else {
                    if(z == z->p->left) RightRotate(z = z->p);
                    z->p->color = BLACK; z->p->p->color = RED; LeftRotate(z->p->p);
                }
            }
        }
        root->color = BLACK;
    }

public:
    RBTree() {
        nil = new Node;
        nil->color = BLACK;
        nil->p = nil->left = nil->right = nil;
        nil->v = Data();
        root = nil;
    }

    ~RBTree() {
        delete root;
        delete nil;
    }

    void insert(Data v) {
        PNode y = nil, x = root;
        while(x != nil) {
            y = x;
            x = v < x->v ? x->left : x->right;
        }
        PNode z = new Node; *z = Node(RED, y, nil, nil, v);
        if(y == nil) root = z;
        else if(v < y->v) y->left = z;
        else y->right = z;
        insertFixUp(z);
    }
};

int main() {
    RBTree<int> tree;
    for(int i = 0; i < 10000000; ++i) tree.insert(i);
    tree.~RBTree();
    getchar();
    return 0;
}

【问题讨论】:

  • 你明确称呼它的事实是错误的。
  • 如果您在 Windows 中通过任务管理器查看内存,内存使用量没有下降是正确的。一个进程一旦获得它就永远不会放弃内存——即使被释放。使用类似 valgrind 的东西来检测内存泄漏。
  • 您的树节点似乎没有递归删除它们的子节点。
  • @roger 给出了答案,这是正确的答案。也许 OP 来自 Java 或 C#,一旦 refs 成为孤儿,你就回家了

标签: c++ destructor red-black-tree


【解决方案1】:

你需要给你的RBNode添加一个析构函数,它会删除它的子元素:

template<class Data> class RBNode {
    ...
    ~RBNode() {
        delete left;
        delete right;
    }
    ...
};

照原样,当树被删除时,您将删除根节点,但根节点本身并不会释放其资源。因此,您丢失了对 root 的子节点及其所有子节点等的所有引用。因为您不再拥有对这些节点的引用,所以无法删除它们,您有内存泄漏。

析构函数确保当我们即将失去对节点子节点的引用时,这些子节点被释放(以及它们的子节点等等)。

【讨论】:

    【解决方案2】:

    首先,问题在于您没有使用智能指针。其次,您没有在 Node 类中使用智能指针,因此当根被删除时,其他对象都不会被删除。

    【讨论】:

      【解决方案3】:

      您的树节点似乎没有递归删除它们的子节点。您需要在节点中使用析构函数,然后当根被销毁时,所有内容都会级联。

      【讨论】:

        【解决方案4】:

        你的析构函数只释放了两个元素:root 和 nil。要释放树的其余部分,您应该以某种方式传播释放树中的元素,例如:

        ~RBNode() {
            if (left != nil ) delete left;
            if (right != nil) delete right;
        }
        

        (这只是想法,当然这段代码不会真正起作用,因为你在析构函数中看不到 nil)。

        【讨论】:

          【解决方案5】:

          我找到了我的析构函数,但我还有一些属性,比如大小和父指针,但我认为它会有所帮助

              ~RBTree() {
                 RBNode *p(root);
                 while(size!=0) {
                    if(p==root && size==1) { delete root; size--;}
                    else if(p->right!=0) p=p->right;
                    else if(p->left!=0) p=p->left;
                    else {
                      RBNode *c(p);
                      p=p->parent;
                      if(p->left==c) {
                          delete c;
                          p->left=0;
                      }
                      else {
                          delete c;
                          p->right=0;
                      }
                      size--;
                    }
                 }
              }
          

          【讨论】:

          • 你也可以递归地做,那么你就不需要父母了:)
          猜你喜欢
          • 2011-08-03
          • 2013-05-02
          • 2016-07-15
          • 2011-08-06
          • 2013-10-27
          • 2011-02-22
          • 1970-01-01
          • 2011-02-04
          • 2012-06-03
          相关资源
          最近更新 更多