C ++:二叉树 - 从父矢量中删除子项

时间:2016-09-06 08:59:15

标签: c++ tree functional-programming

我有这个结构:

#include <stddef.h>
#include <vector>

typedef int T;
class tree; 

class node {
    T info;
    std::vector<node*> children;
    friend class tree;
public:
    typedef std::vector<node*>::iterator iterator;
    iterator begin() {
        return children.begin();
    }
    iterator end() {
        return children.end();
    }
    T get() {
        return info;
    }
};

class tree {
    node* r;
    void del(node* v) {
        if (v == NULL) return;
        for (node::iterator it = v->begin(); it != v->end(); ++it)    
            del(*it);
        delete v;
    }
public:
    tree() : r(NULL) { }
    node* add(T info, node* parent) {
        node* v = new node;
        v->info = info;
        if (parent != NULL) parent->children.push_back(v);
        else {
            if (r != NULL) del(r);
            r = v;
        }
        return v;
    }
node* add(T info) {

        return add(info, NULL);
    }
    node* root() { return r; }
    void remove(node* v) {
        if (r == v) r = NULL;
        else { /* remove v from the list of children of its parent */ }
        del(v);
    }
};

我需要通过从父项列表中删除节点v来完成删除功能。为了有效地这样做,我将向节点类添加指向其父节点的指针并相应地更新add函数。 这是我的解决方案 我用以下方法修改了添加功能:

 node* add(T info, node* parent) {
    node* v = new node;
    v->info = info;
    if (parent != NULL) {
         parent->children.push_back(v);
         v->parent=parent; }
    else {
         if (r != NULL) del(r);
         r = v;
         r->parent=null;
          }
    return v;
}

我将删除功能修改为:

  void remove(node* v) {
        if (r == v) r = NULL;
        else { 
         v->parent->children.pop_back(v);  
         }
        del(v);
    }

这在概念上是否正确?不幸的是,类pop_back method的{​​{1}}不允许这种参数,所以这会返回错误。 这是正确的还是我应该使用其他实现?

抱歉,我对c ++并不熟悉。感谢

2 个答案:

答案 0 :(得分:0)

pop_back从矢量中删除最后一个元素 - 无论哪个......

请改为尝试:

std::vector<node*>::iterator entry = std::find(v->parent->begin(), v->parent->end(), v);
if(entry != v->parent->end())
    v->parent->erase(entry);

或更短:

auto entry = std::find(v->parent->begin(), v->parent->end(), v);
/* ... */

变体将使用std :: remove:

v->parent->erase(std::remove(v->parent->begin(), v->parent->end(), v), v->parent->end());

std::remove通过将所有后续元素移动到开头的适当数量的位置(如果有的话),删除给定范围内的所有发生的所有(假设它只有一个...)元素已被删除,一个位置,如果两个元素,两个位置,...)并将迭代器返回到最后一个仍在使用中的位置。但是,从这里开始的元素仍然保留在向量(或列表或...)中,因此您必须删除这些元素,这是由vector::erase函数的第二个变量... < / p>

关于这个概念:有一点对我很重要:如果parent为null,则要删除root。但是,如果root有孩子本身呢?你会在del函数中递归删除它们吗?你确定你真的想要替换已经包含的整个树吗?可能最好让r成为v的孩子呢?

但现在不要将此解释为&#34;你应该这样做&#34; - 这只是一个考虑的建议 - 但我不知道你的要求,所以由你来决定......只有一件重要的事情:如果删除它,不要忘记删除节点的子节点,否则你有内存泄漏...

除此之外,乍一看你的概念对我来说还不错......

编辑:在评论中回答问题:相应的析构函数如下所示:

~node()
{
    for(node* n : children)
    {
        delete n;
    }
}

这会递归删除所有子节点的所有节点。然后,您需要做的就是清除整个树

delete r;
r = nullptr;

即G:

void clear()
{
    delete r;
    r = nullptr;
}
~tree()
{
    clear();
}

我认为您不打算允许这样做,但如果您的节点插入多个子矢量中,您将陷入深深的麻烦!

因此,如果您计划稍后重新显示节点,请记住从之前的父节点列表中删除节点。如果你想保留一些子节点,你需要先将它们从树中取出来。当然。

答案 1 :(得分:0)

实际上我做了类似的事情:

~tree()
{
    for(node::iterator it=r->children.begin(); it!=r->children.end(); ++it)
    {
        (*it)->info=NULL;
        node* tmp= new node;
        tmp=(*it);
        delete tmp;   
    }
    r->info=NULL;
    delete r; //Dealloco la memoria riservata ad r
}