C++ 删除节点及其子节点

时间:2021-02-05 09:52:31

标签: c++ c++17

请帮帮我。我被困在这一点上。 我想做什么:二叉搜索树。 我是一名 C# 开发人员,我学习 C++ 大约 2 周,因此不要对我这么苛刻,这就是为什么指针对我来说仍然很困难。

我有一个结构节点

struct Node
    {
        int Value;

        Node* _LeftNode;
        Node* _RightNode;

        Node(int value)
            : Value(value), _LeftNode(NULL), _RightNode(NULL)
        {
        }
    }; 

和 BinarySearchTree.cpp 中的 Delete() 函数

void BinarySearchТрее::Delete(Node* node)
{
    if (node)
    {
        Delete(node->_LeftNode);
        Delete(node->_RightNode);
        delete(node);
        node = NULL;
    }
}

我想删除该节点及其所有子节点。 当我开始递归时......例如: Enter the recursion

我有两个值分别为 10 和 19 的子节点。 通过递归,我删除节点并将指针设置为 NULL。 NULL node

问题来了: 当我从递归中出来时,节点不是 NULL,而是一些奇怪的东西。 After recursion

这是我的问题。为什么当我在递归中并且我为 NULL 指针时一切正常,但是当我出来时指针是别的东西。

4 个答案:

答案 0 :(得分:0)

正如我在评论中所说,我认为问题是我们如何重置最初传递的节点的父节点(左或右子节点)的指针。 (递归删除一个节点及其所有子节点看起来不错。)

而且我认为在您当前的设计中是不可能的。由于 Node 不包含指向其父级的指针,因此无法知道谁是父级。 node = NULL 只设置参数(局部变量)的值,所以它毫无意义。

答案 1 :(得分:0)

给定:

struct Node
{
    int data = 0;
    struct Node * left = nullptr, * right = nullptr;

    Node(int data) { this->data = data; }
};

这个递归函数删除一个节点及其子节点(+一条评论):

void DeleteTree(struct Node* node) // A copy of the caller pointer
{
    if (node)
    {
        DeleteTree(node->left);   // Recur on left subtree
        DeleteTree(node->right);  // Recur on right subtree
        delete node;
        // node = nullptr; <-- This line is useless
    }
}

你想知道“但是当我出来时,指针是别的东西”: node = nullptr 行没有任何意义,因为当您调用 DeleteTree(my_node) 函数时,nodemy_mode 的副本,因此当您设置 node = nullptr 时它没有对 my_node 的影响,从 DeleteTree(my_node) 退出时指向一个已删除的无效对象。

--

可能的解决方案:

#define DELETE_TREE(node) DeleteTree(node); node = nullptr; // Macro

int main()
{
    struct Node* root   = new Node(1);
    root->left          = new Node(2);
    root->right         = new Node(3);
    root->left->left    = new Node(4);
    root->left->right   = new Node(5);

    DELETE_TREE(root->left); // root->left became nullptr  
    DELETE_TREE(root); // root became nullptr

    return 0;
}

DeleteTree 函数之后,调用者指针指向一个无效的对象,因为它的对象已经被释放。一个可能的解决方案是在 DELETE_TREE 函数之后定义一个 DeleteTree 宏来“自动取消”调用者指针。

--

使用现代 C++ 智能指针实现:

#include <memory>

struct Node
{
    int data = 0;
    std::unique_ptr<Node> left, right;

    Node(int data) { this->data = data; }
};

int main()
{
    std::unique_ptr<Node> root;

    root                = std::make_unique<Node>(1);
    root->left          = std::make_unique<Node>(2);
    root->right         = std::make_unique<Node>(3);
    root->left->left    = std::make_unique<Node>(4);
    root->left->right   = std::make_unique<Node>(5);

    root.reset();

    return 0;
}

答案 2 :(得分:0)

C++ 的方式是使用 std::unique_ptr

struct Node
{
    int Value;

    std::unique_ptr<Node> LeftNode;
    std::unique_ptr<Node> RightNode;

    Node(int value)
        : Value(value)
    {
    }
};

然后要销毁一个节点及其所有子节点,您可以在相应的 reset

上调用 std::unique_ptr<Node>

答案 3 :(得分:0)

我认为你真正想要的是这个:

struct Node
{
    int Value;

    Node* _LeftNode;
    Node* _RightNode;

    Node(int value)
        : Value(value), _LeftNode(NULL), _RightNode(NULL)
    {
    }

    ~Node() {
       delete _LeftNode;
       delete _RightNode;
    }
}; 

这样你就可以使用析构函数来递归地清理。 顺便说一句,delete nullptr 没问题。

编辑:

其他答案之一中的 unique_ptr<> 用法可能是更明智的方法。

相关问题