使用C ++实现我自己的BST,以获得处理此类结构的经验。
我在实现析构函数时遇到了麻烦。我在学习中发现,一个人不能真正有一个递归的析构函数(由于一个标志不允许在被调用后在同一个对象上调用析构函数),但我不确定是否另一种成功清理树中所有节点的方法。
为了补偿,我创建了一个辅助函数 - 但是这会在'delete n'行引发一个未解决的外部错误。有什么提示吗?
代码:
void BinSearchTree::Clear(tNode* n)
{
if (n->left != NULL)
Clear(n->left);
if (n->right != NULL)
Clear(n->right);
delete n;
n = NULL;
size--;
}
答案 0 :(得分:19)
你可以有一个递归的析构函数;你不能做的是两次删除同一个对象。
在C ++中删除树的典型方法可能是这样的:
BinSearchTree::~BinSearchTree()
{
delete _rootNode; // will recursively delete all nodes below it as well
}
tNode::~tNode()
{
delete left;
delete right;
}
关于未解决的外部错误 - 当您尝试编译/链接程序时抛出的错误是什么?如果是这样,可能是因为tNode类的代码(特别是tNode析构函数,如果你声明了它)不存在或者没有被编译到你的项目中。
答案 1 :(得分:4)
以前的答案指出,未解决的外部错误可能是由于链接器可以看到的转换单元中声明但未定义的tNode析构函数引起的。
但是,您有第二个错误:您似乎认为将n设置为null会执行其不执行的操作。指针值n按值传递,而不是通过引用传递,因此在函数返回后更改其值(例如,通过赋值NULL)无效。
当你清除树并期望根节点指针被设置为NULL时,它可能会给你错误,当它仍然是一个悬浮指针释放内存时。结果将是运行时错误,而不是链接器错误。
void BinSearchTree::Clear(tNode **N)
{
tNode * n = *N;
if (n->left != NULL)
Clear(n->left);
if (n->right != NULL)
Clear(n->right);
delete n;
*N = NULL;
size--;
}
会做你期望的事。
答案 2 :(得分:3)
问题是,在你的类中你可能声明节点结构有一个自定义析构函数,但你没有提供它,所以在链接时编译器抱怨缺少一块。
如果你在析构函数中不需要任何更多的自定义代码,那么你可以从struct声明中删除析构函数,你的程序就可以正常编译。
但是请注意,对于destory children节点的析构函数完全没有问题(参见Brendan Long的回答)。如果您在尝试遇到问题时遇到问题,那么我必须提出其他问题。
答案 3 :(得分:1)
只需使用析构函数。听起来你的问题是你试图直接调用析构函数,但语言会为你处理这个问题。当你离开堆栈分配对象的范围或者删除对象时,它们会被调用。
你需要的只是:
~BinSearchTree() {
delete left;
delete right;
}
delete
会调用他们的析构函数。
注意:delete NULL
has no effect非常安全。
答案 4 :(得分:1)
如何实现自动化:
class BinSearchTree
{
std::auto_ptr<tNode> left;
std::auto_ptr<tNode> right;
BinSearchTree(BinSearchTree const&);
BinSearchTree& operator=(BinSearchTree const&); // private
};
现在销毁是自动的。 : - )
答案 5 :(得分:0)
您也可以使用递归,只需将函数标题更改为:
void remove(node*& root)
它会起作用。