我有一个BinarySearchTree结构:
struct BSTNode {
int value;
BSTNode *left = nullptr;
BSTNode *right = nullptr;
};
struct BST {
BSTNode *root = nullptr;
};
使用这个树的一些函数:
BSTNode **findPosition(BSTNode *node, int value) {
if (value < node->value) {
if (node->left) {
return findPosition(node->left, value);
} else {
return &node->left;
}
}
if (value > node->value) {
if (node->right) {
return findPosition(node->right, value);
} else {
return &node->right;
}
}
return &node;
}
void remove(BSTNode** position, int value) {
if ((*position)->left == nullptr && (*position)->right == nullptr) {
delete (*position);
*position= nullptr;
}
}
void remove(BST &bst, int value) {
BSTNode **position = findPosition(bst.root, value);
if (*position != nullptr) {
remove(position,value);
}
}
void add(BSTNode *node, int value) {
BSTNode **position = findPosition(node, value);
BSTNode *newNode = new BSTNode;
newNode->value = value;
*position = newNode;
}
void add(BST &bst, int value) {
if (!bst.root) {
BSTNode *root = new BSTNode;
root->value = value;
bst.root = root;
} else {
add(bst.root, value);
}
}
添加工作正常,但删除元素工作奇怪(现在它应该只适用于叶节点)。它只是将节点的值设置为零。我认为问题在于我使用指针。
我做错了什么?
答案 0 :(得分:1)
return &node;
中的最终案例FindPosition
是错误的。它返回垃圾。
如果您将签名更改为
BSTNode **findPosition(BSTNode *&node, int value)
然后在许多用途中将修复最终的回报。我没有(或取决于你有什么与你发布的内容不能)检查所有用途,看看是否涵盖了你使用findPosition的各种方式。
在不更改签名的情况下,您将返回调用参数的地址,该地址在返回值可以使用时无效。通过该签名更改,相同的返回指令将返回正确的地址。 但签名更改表示对findPosition与其调用方之间的合同进行了重大更改,因此仅当所有调用方的更改都正常时,它才有效。否则,你需要做出更大的改变。没有改变只是findPosition可以工作而不改变与其调用者的合同。
编辑(因为你的评论)。在最终返回指令中,您需要返回该指针的原始地址。如果没有签名更改,则返回指针副本的地址。通过签名更改,函数的语法仍然将node
视为指针,但在其语义中隐藏了额外的间接级别。使用额外的间接级别,该指针的原始地址可用(并由&node
计算)而不是副本的地址。
另外(基于dasblinkenlight的答案)在你的版本的许多地方都需要测试NULL指针,这很容易出错。如果您将该测试推送到findPosition的顶部,则需要更少的位置且更强大:
BSTNode **findPosition(BSTNode *&node, int value) {
if ( node )
{
if (value < node->value) {
return findPosition(node->left, value);
}
if (value > node->value) {
return findPosition(node->right, value);
}
}
return &node;
}
答案 1 :(得分:1)
在/usr/local/include/boost/serialization/access.hpp:118:9: error: 'class boost::tuples::tuple<int, int, int, int, int>' has no member named 'serialize'
t.serialize(ar, file_version);
,
findPosition
返回参数的地址 在函数之外取消引用它是未定义的。
目前还不清楚为什么函数会返回一个指针的地址。
您需要重新考虑删除策略;为了删除节点,您需要修改其父节点的子指针。
答案 2 :(得分:1)
您的代码有未定义的行为:
return &node;
返回函数参数的地址,这意味着任何取消引用findPosition
的返回值都会导致未定义的行为。
您可以通过确保findPosition
引用指针而不是指针来避免此问题:
BSTNode **findPosition(BSTNode*& node, int value) {
if (node == nullptr) {
return &node;
}
... // The rest of the code remains the same
}
请注意,虽然return &node
的语法保持完全相同,但行为却不同,因为在函数退出后,引用指针的地址仍然有效。
注意:除非这是使用C ++语法编写C代码的学习练习,否则请考虑重构代码以在BSTNode
内封装BST
,并将树功能公开为成员功能