我有这个结构:
#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 ++并不熟悉。感谢
答案 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
}