请帮帮我。我被困在这一点上。 我想做什么:二叉搜索树。 我是一名 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;
}
}
我想删除该节点及其所有子节点。 当我开始递归时......例如:
我有两个值分别为 10 和 19 的子节点。 通过递归,我删除节点并将指针设置为 NULL。
问题来了: 当我从递归中出来时,节点不是 NULL,而是一些奇怪的东西。
这是我的问题。为什么当我在递归中并且我为 NULL 指针时一切正常,但是当我出来时指针是别的东西。
答案 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)
函数时,node
是 my_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<>
用法可能是更明智的方法。