假设我的删除尝试按顺序(从左到右)重新平衡树。
我正在编写一个BinarySearchTree类,我的删除功能目前正常工作(我相信 - 我希望< 3)在大多数情况下。我有几个边缘案件可以抗衡:
提出的根删除解决方案:
我的解决方案,即删除根并使用我的BST类的成员函数将setRoot设置为New(使该节点成为根),然后将New曾经设置为0 / NULL。
答:这有效,但我必须把案件工作放在一起。
在BST类中有一个虚拟父节点,它只是将根节点作为它的右手对象(由billyswong建议)。
答:这可能有用,但我觉得我应该有特殊的案例来处理它。
删除两个孩子的建议解决方案:
我的解决方案是暂时存储New的位置,将New的位置设置在New的右子项中,然后删除临时指针。
答:这样可行,但不像我想的那样优雅。
这是我的代码:
if (root()->value() == val)
{
delete root();
this->setRoot(New);
newCurr->setLeft(0);
}
else if (newCurr == next)
{
Node *temp = New;
newCurr->setRight(New->right());
delete temp;
}
海报请告诉我这段代码1)是否有效2)是最佳的。
编辑:抱歉我在功能结束时对camelcaps的使用不一致。我想不出对我的变量名更好的描述,但new
是C ++中定义的关键字。
Edit2:发布了重构代码,但错误仍然存在。
void BinarySearchTree::del(int val)
{
//curr refers to the parent of next
//next is the node we will want to delete
Node* curr = 0;
Node* next = root();
//these will only be used if you get into
//the last case, where you have two children
//on next
Node* newCurr = curr;
Node* New = next;
//boolean value to check if you found the value
//in the binary search tree
bool found;
//set curr and next; will be false if val not found
found = setCurrAndNext(val, curr, next);
//get next to the node needing deletion
//and set curr to its parent
//pass by ref function
//return value is that you found it
if (found)
{
setNewCurrAndNew (newCurr, New);
}
else
{
return;
}
/* next is a leaf */
if (nextIsLeaf(next))
{
handleLeafCase(curr, next);
return;
}
/* next has a single child */
else if (nextHasSingleChild(next))
{
if(leftIsChild(next))
{
handleLeftCase(curr, next);
}
else
{
handleRightCase(curr, next);
}
}
/* next has two children */
else
{
if (newCurr == next)
{
Node *temp = New;
newCurr->setRight(New->right());
delete temp;
}
else if (next == curr->left())
{
if (New == newCurr->left())
{
curr->setLeft(New);
newCurr->setLeft(next);
}
else
{
curr->setLeft(New);
newCurr->setRight(next);
}
}
else
{
if (New == newCurr->left())
{
curr->setRight(New);
newCurr->setLeft(next);
}
else
{
curr->setRight(New);
newCurr->setRight(next);
}
}
if (next->left() == 0 && next->right() == 0)
{
newCurr->setRight(0);
newCurr->setLeft(0);
delete next;
}
else
{
if (next->left() == 0)
{
newCurr->setRight(next->left());
}
else
{
newCurr->setLeft(next->right());
}
delete next;
}
}
}
}
答案 0 :(得分:1)
删除根节点将不起作用,因为它没有父节点
我对这一点的想法是,给你的根一个虚拟的父节点,一个节点不包含实际有用的值,但根节点作为它的右子节点。然后,每个可删除节点都将拥有其父节点,并且root()将能够像其他节点一样更加统一地处理。那么你也不需要特殊的方法来记住树是否也是空的。
修改:found = setCurrAndNext(val, curr, next);
如何设置curr
和next
? AFAIK C / C ++总是按值传递。我在辅助函数中闻到了一些错误。
答案 1 :(得分:1)
我不能给你代码或任何东西,但你正在寻找的是一个“旋转”操作符。基本上,它处理“烦人”的删除情况 - 当你删除一个有两个孩子的树,这两个孩子都有两个孩子,比如根,还有树中的任何其他节点。
旋转的作用基本上是在所涉及的节点之间,在一个非常局部的区域中交换孩子(创伤,我知道),以便保持孩子的排序(左边较小,右边较大)。它类似于优先级队列的“冒泡”功能。
这是维基百科(http://en.wikipedia.org/wiki/Tree_rotation)页面。
希望这能让你走上正轨!
编辑以回应评论: 对不起,我应该解释一下。当我说“树”时,我的意思是节点,维基百科页面应该仍然有用。由于二进制搜索树的数学递归定义,您可以将每个节点视为自己的子树,因此我的初始语句(保持不变)。但这只是与你的问题相关,所以继续......:)