【问题标题】:Delete single element in Binary Search Tree (C++)删除二叉搜索树中的单个元素 (C++)
【发布时间】: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-&gt;left_this-&gt;right_ 设置为 nullptr - 这是修复它的方法吗?
  • 基本问题——为什么BstNode 甚至有一个破坏左右树的析构函数?如果您只想删除那个节点怎么办?以“经典”方式执行此操作更简单,您可以在其中遍历要删除的节点,隔离该节点,通过算法将现有分支拼接到要删除的节点所在的位置,然后删除您之前隔离的节点。这样您就不必担心试图避免“级联删除”调用。
  • 级联删除是为了防止内存泄漏 - 如果您在函数中创建了 BstNode,除非您以某种方式递归删除每个子节点,否则您将在该函数结束时泄漏内存。
  • 级联删除是为了防止内存泄漏——这仍然没有解决我指出的问题——如果你只想删除那个节点怎么办?在删除节点之前,您必须将左侧和右侧都清空,这样您的析构函数就不会搞砸工作。
  • 是的,BstNode::Delete 函数旨在删除一个节点而不是整个子树——这就是为什么当我尝试我的代码并且它有效时我有点困惑。就像@1201ProgramAlarm 所说,事实证明你会得到悬空指针——这“很好”(不是真的),直到你稍后重新使用那个内存位置(我想?)。我想我喜欢在删除this之前先将left_right_设置为nullptr的方法,因为这样我一直在防止内存泄漏。

标签: c++ oop binary-search-tree


【解决方案1】:

BstNode* temp=left_BstNode* temp=right_ 会将 left_ 或 right_ 的值存储在临时变量中。在将值存储在 temp 中之后,您正在使用 delete this;。现在,在您使用delete this; 之后,left_ 和 right_ 将被删除,但 temp 仍将保持不变。 delete this; 不会影响 temp 的值(它具有您的左/右子树),您现在可以在相应的右/左子树被删除后返回相应的左/右子树(在这种情况下,无论是 left_或 right_ 指向 NULL)。我希望这有帮助! 此外,在指向未分配 new 的对象的指针上使用 delete 会产生不可预测的结果,所以要小心!

【讨论】:

  • 哎呀,是的,好点子!我必须确保在使用它的代码中始终使用new BstNode()。这只是我对一些 C++ 的复习,但实际上我可能会创建一个包装类来对用户隐藏 BstNodes。谢谢!
  • 我认为指针的副本对您没有帮助,因为您正在破坏整个子树。你会得到悬空指针,就像@1201ProgramAlarm 说的那样。
【解决方案2】:

由于您的 BstNode 析构函数删除了 left_right_ 节点,因此您会遇到此序列导致的未定义行为:

BstNode* temp = right_;
delete this;
return temp;

delete this 语句之后,temp 将成为一个悬空指针,因为它指向的对象已被删除。您返回该指针,并将其存储回另一个节点,最终当您取消引用该节点时,任何事情都可能发生 - 包括程序似乎正常工作。

您应该在调用删除之前将right_ 设置为nullptr,或者更改析构函数(和整体销毁顺序)以不删除子节点。

【讨论】:

  • 啊,好的。所以我认为这很危险是正确的——我只是假设 C++ 会改变这些值(为零或什么?),但在考虑了一段时间后,我想这将是不必要的工作。我将在删除this 之前将right_(或left_)设置为nullptr,然后。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多