为什么我的 C++代码无法删除我的 BST 中的所有节点?

发布于 2024-08-21 00:14:28 字数 659 浏览 3 评论 0原文

这应该遍历 BST 并删除每个节点,包括根节点。然而,最后,我收到消息“根仍然有一个左节点”。为什么没有删除所有节点?

void deleteTree()
{   
    deleteNode(root);
    if(root->right)
        cout << "root still has a right node" << endl;
    if(root->left)
        cout << "root still has a left node" << endl;
    root = 0;

}   

void deleteNode(node *p) 
{   
    if(p->left) 
    {   
        deleteNode(p->left);
        p->left = 0;
    }   
    if(p->right) 
    {   
        deleteNode(p->right);
        p->right = 0;
    }   

    cout << "Deleting node containing " << p->data << endl;
    delete p;
}   

This is supposed to traverse a BST and delete every node, including the root node. However, at the end, I get the message "root still has a left node." Why aren't all nodes deleted?

void deleteTree()
{   
    deleteNode(root);
    if(root->right)
        cout << "root still has a right node" << endl;
    if(root->left)
        cout << "root still has a left node" << endl;
    root = 0;

}   

void deleteNode(node *p) 
{   
    if(p->left) 
    {   
        deleteNode(p->left);
        p->left = 0;
    }   
    if(p->right) 
    {   
        deleteNode(p->right);
        p->right = 0;
    }   

    cout << "Deleting node containing " << p->data << endl;
    delete p;
}   

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

她说她爱他 2024-08-28 00:14:28

您正在删除末尾的 p (root),然后尝试在 deleteTree() 中访问其内容,其中 root 不再指向分配的内存。结果将是不确定的。

Your are deleting p at the end (root) and then trying to access its contents in deleteTree(), where root no longer points to allocated memory. The result is going to be undefined.

小帐篷 2024-08-28 00:14:28

您正在删除root。然后你的代码尝试访问原来的内存。

你已经进入了未定义行为领域。

You're deleting root. And then your code is trying to access memory where it was.

You're well into undefined-behaviour land there.

℉絮湮 2024-08-28 00:14:28

deleteNode 中删除 root 后,不应取消引用它。使用调试器检查为什么 root->left 不为空。

You should not dereference root after you delete it in deleteNode. Use a debugger to inspect why root->left is non-null.

帝王念 2024-08-28 00:14:28

在删除根之后,您将查看root->left,使其可在新分配的块中使用。

You are looking at root->left after you've already deleted root, making it avalable for use in a new allocated block.

断爱 2024-08-28 00:14:28

我只需更改树本身,这样处理它就会更容易:

struct Node
{
  Node(data_type data): mLeft(), mRight(), mData(data) {}
  Node(const Node& rhs): mLeft(), mRight(), mData(rhs.mData)
  {
    if (rhs.mLeft.get()) mLeft.reset(new Node(*rhs.mLeft));
    if (rhs.right.get()) mRight.reset(new Node(*rhs.mRight));
  }
  Node& operator=(Node rhs)
  {
    this->swap(rhs);
    return *this;
  }
  ~Node() { }

  void swap(Node& rhs)
  {
    using std::swap;
    swap(mLeft, rhs.mLeft);
    swap(mRight, rhs.mRight);
    swap(mData, rhs.mData);
  }

  Node* left() const { return mLeft.get(); }
  void left(std::auto_ptr<Node> node) { mLeft= node; }

  Node* right() const { return mRight.get(); }
  void right(std::auto_ptr<Node> node) { mRight = node; }

  data_type& data() { return mData; }
  const data_type& data() const { return mData; }

private:
  std::auto_ptr<Node> mLeft;
  std::auto_ptr<Node> mRight;
  data_type mData;
};

通过面向对象,每个节点现在负责它处理的内存。此外,在界面中使用 std::auto_ptr 可以清楚地表明它获取所有权。

请注意,它是为深度复制、任何其他需要 boost::shared_ptr 或等效方法的方法量身定制的。是的,std::auto_ptr 让您自己处理复制,这没有什么魔力。

这种设计比使用普通的 C 结构要干净得多,每个人都可以操作资源。您仍然可以通过访问器完全访问底层数据...但是他们注意不要调用未定义的行为...

当然,您仍然可以将其崩溃:

Node& node = ...
delete node.left(); // haha

但是如果 C++ 可以防止意外问题,那么它就留下了大门对邪恶代码开放。

I would simply change the tree itself, it would be easier to deal with it then:

struct Node
{
  Node(data_type data): mLeft(), mRight(), mData(data) {}
  Node(const Node& rhs): mLeft(), mRight(), mData(rhs.mData)
  {
    if (rhs.mLeft.get()) mLeft.reset(new Node(*rhs.mLeft));
    if (rhs.right.get()) mRight.reset(new Node(*rhs.mRight));
  }
  Node& operator=(Node rhs)
  {
    this->swap(rhs);
    return *this;
  }
  ~Node() { }

  void swap(Node& rhs)
  {
    using std::swap;
    swap(mLeft, rhs.mLeft);
    swap(mRight, rhs.mRight);
    swap(mData, rhs.mData);
  }

  Node* left() const { return mLeft.get(); }
  void left(std::auto_ptr<Node> node) { mLeft= node; }

  Node* right() const { return mRight.get(); }
  void right(std::auto_ptr<Node> node) { mRight = node; }

  data_type& data() { return mData; }
  const data_type& data() const { return mData; }

private:
  std::auto_ptr<Node> mLeft;
  std::auto_ptr<Node> mRight;
  data_type mData;
};

By being Object-Oriented, each Node is now responsible for the memory it handles. Also, using std::auto_ptr in the interface makes it clear that it takes ownership.

Note that it's been tailored for deep-copying, any other approach requiring boost::shared_ptr or equivalent. And yes std::auto_ptr leaves you dealing with copying by yourself, no magic there.

This design is much cleaner than using a plain C-struct with everyone being able to manipulate the resources. You still have full access to the underlying data via the accessor... but THEY take care not to invoke undefined behavior...

Of course, you can still crash it down:

Node& node = ...
delete node.left(); // haha

But if C++ may protect against unintended issues, it leaves the door open to evil code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文