我有一个函数用于在二叉搜索树中查找指定节点以及节点以前的节点:
bool collection::removeFromTree(const char name[])
{
treeNode ** prev = nullptr;
for (treeNode ** curr = &root; *curr;)
{
int8_t result = strcmp(name, (*curr)->item->getName());
if (result == 0)
{
deleteNode(prev, curr);
return true;
}
else if (result < 0)
{
prev = curr;
curr = &((*curr)->left);
}
else if (result > 0)
{
prev = curr;
curr = &((*curr)->right);
}
}
return false;
}
我遇到的问题不在于此功能,而在于我的deleteNode()
功能。我无法指定我的上一个节点指向当前节点(或我计划删除的节点)之后的节点。这是我deleteNode()
函数的重要部分:
void collection::deleteNode(treeNode **& prevNode, treeNode **& goneNode)
{
//irrelevant code
//if it has right child
if (!(*goneNode)->left)
{
treeNode * temp = (*goneNode)->right;
(*goneNode)->right = nullptr;
delete *goneNode;
(*prevNode)->right = temp;
*goneNode = nullptr;
}
//irrelevant code
}
问题当然是(*prevNode)->right
在此函数运行后变为null
。指向指针的指针超出范围,数据丢失。位于goneNode右侧的任何节点都超出了范围。有什么好方法可以解决这个问题吗?
我也尝试过:
void collection::deleteNode(treeNode **& prevNode, treeNode **& goneNode)
{
//irrelevant code
//if it has right child
if (!(*goneNode)->left)
{
(*prevNode)->right = (*goneNode)->right;
(*goneNode)->right = nullptr;
delete *goneNode;
*goneNode = nullptr;
}
//irrelevant code
}
当我这样做时,(*prevNode)->right
在null
之后(在函数执行完成之前)变为delete *goneNode;
。
答案 0 :(得分:0)
这里使用双星指针的好处是避免使用current
和previous
指针。有一个指向指向节点的指针,我们可以编辑将该节点绑定到树中的链接。前一个节点的其余部分并不重要;我们只关心指向我所谓的bad_node
(要删除的那个)的指针。
(*prevNode)->right = (*goneNode)->right; //50% chance that (*prevNode)->right was (*goneNode)
bad_node
位于prevNode
的右侧,我们删除了bad_node
的位置,或者它位于左侧,我们将树木毁了。我在你的场景中投注第一个正在发生的事情。一旦该行执行,*goneNode
将是错误的值,因此它最终会泄漏goneNode
并删除其子项。
else if (!(*goneNode)->left) //one child on right
{
treeNode* temp = *goneNode; //store address of bad_node
*goneNode = (*goneNode)->right; //replace bad_node with child
temp->right = nullptr; //bad_node now has no children
delete temp; //delete bad_node
}
要记住的重要一点是,*goneNode
是指向树中<{1}} 的指针。分配给bad_node
会更改树的结构。