【发布时间】:2018-10-04 05:58:09
【问题描述】:
我做了一个二叉搜索树(节点)类:
class BstNode {
public:
BstNode(int value);
~BstNode();
BstNode* Delete(int value);
// more methods
private:
int value_;
BstNode* left_;
BstNode* right_;
};
使用如下所示的析构函数:
BstNode::~BstNode() {
delete left_;
delete right_;
}
还有一个Delete 函数:
BstNode* BstNode::Delete(int value) {
// If the value to be deleted is smaller than the root's key,
// then it lies in the left subtree.
if (value < value_) {
if (left_ == nullptr) return nullptr;
else left_ = left_->Delete(value);
}
// If the value to be deleted is larger than the root's key,
// then it lies in the right subtree.
else if (value > value_) {
if (right_ == nullptr) return nullptr;
else right_ = right_->Delete(value);
}
// If the key to be deleted is the same as root's key, then *this*
// is the node to be deleted.
else {
// If this node has no children, then we can just delete it.
if (left_ == nullptr && right_ == nullptr) {
delete this;
return nullptr;
}
// If this node has one child, then we can just set this node to
// that child and delete this node afterwards.
else if (left_ == nullptr) {
BstNode* temp = right_;
delete this;
return temp;
}
else if (right_ == nullptr) {
BstNode* temp = left_;
delete this;
return temp;
}
// If this node has two children, then we have to get the "in-order successor"
// (the smallest node in the right subtree).
else {
BstNode *temp = right_->Smallest();
// Copy that node's value to this node
value_ = temp->value_;
// Then delete that value from the right subtree
right_ = right_->Delete(value_);
}
}
return this;
}
我很困惑的是这个sn-p:
else if (left_ == nullptr) {
BstNode* temp = right_;
delete this;
return temp;
}
else if (right_ == nullptr) {
BstNode* temp = left_;
delete this;
return temp;
}
如果对delete 的调用调用了类的析构函数,我最终不会删除整个子树(右侧或左侧)吗?但是,在测试时,看起来树正在做我希望它做的事情:删除一个节点,并将子子树“向上移动”到“this”所在的位置 - 子树仍然完好无损。
据我所知,执行BstNode* temp = this; 只会将指针 复制到left_ 和right_,然后delete this 调用应该会破坏它们背后的数据。
我是否错过了关于 delete this 的某些内容?
【问题讨论】:
-
顺便说一句,我认为更安全的做法是在删除
this之前将this->left_和this->right_设置为nullptr- 这是修复它的方法吗? -
基本问题——为什么
BstNode甚至有一个破坏左右树的析构函数?如果您只想删除那个节点怎么办?以“经典”方式执行此操作更简单,您可以在其中遍历要删除的节点,隔离该节点,通过算法将现有分支拼接到要删除的节点所在的位置,然后删除您之前隔离的节点。这样您就不必担心试图避免“级联删除”调用。 -
级联删除是为了防止内存泄漏 - 如果您在函数中创建了 BstNode,除非您以某种方式递归删除每个子节点,否则您将在该函数结束时泄漏内存。
-
级联删除是为了防止内存泄漏——这仍然没有解决我指出的问题——如果你只想删除那个节点怎么办?在删除节点之前,您必须将左侧和右侧都清空,这样您的析构函数就不会搞砸工作。
-
是的,
BstNode::Delete函数旨在删除一个节点而不是整个子树——这就是为什么当我尝试我的代码并且它有效时我有点困惑。就像@1201ProgramAlarm 所说,事实证明你会得到悬空指针——这“很好”(不是真的),直到你稍后重新使用那个内存位置(我想?)。我想我喜欢在删除this之前先将left_和right_设置为nullptr的方法,因为这样我一直在防止内存泄漏。
标签: c++ oop binary-search-tree