2013-10-29 65 views
0

我想删除特定的节点,但我没有看到问题出在哪里。如何删除特定节点是二叉搜索树?

其实,我通过Find()得到节点,然后用Remove()删除它。

该程序崩溃,每当Delete()火灾。

bool RemoveNode(int key) 
{ 
    if (IsEmpty()) 
     return false; 
    Node* r = Find(key,root); 
    if (r==nullptr) 
     return false; 
    return Remove(r); 
} 
bool Remove (Node* &r) 
{ 
    if (r->left==nullptr && r->right ==nullptr) 
    { 
     delete r; 
     r=nullptr; 
     return true; 
    } 
    if (r->left==nullptr) 
    { 
     Node* temp = r->right; 
     delete r; 
     r=nullptr; 
     r=temp; 
     return true; 
    } 
    if (r->right==nullptr) 
    { 
     Node* temp = r->left; 
     delete r; 
     r=nullptr; 
     r=temp; 
     return true; 
    } 
    Node* Max = FindMax(r->left); 
    r->data = Max->data; 
    Remove(Max); 

    return true; 
} 
Node* FindMax(Node* r) 
{ 
    if(r->right==nullptr) 
     return r; 
    return FindMax(r->right); 
} 
Node* Find(int key, Node* &r) 
{ 
    if (r==nullptr) 
     return nullptr; 

    if (r->data==key) 
     return r; 

    if (key < r->data) 
     return Find(key,r->left); 
    else 
     return Find(key,r->right); 
} 
+2

难道你不需要更新“父”,不再指向已删除的子节点吗? – Justin

+2

你使用过调试器吗? – clcto

回答

1

显然,你Remove()功能旨在修改指针节点,独立于所在:不是传递的原始指针,你传递给指针的引用。这样,您可以将树的root指针,leftright更新为下一个的组成部分。只要你将它传递给正确的参考,我认为代码应该工作。的Find()结果是一个指针,而不是相关的指针的引用:

可变rRemove()这是在RemoveNode()定义的本地变量实际上修改。但是,您需要修改指向该节点的树结构中的指针,而不是任意的局部变量。

的解决将是使用Find()' which correctly returns a reference to the pointer rather than the pointer itself. Your recursive查找()would be up to the task if it returned a节点* & rather than a节点*`的一个特殊版本。由于你的树似乎并不平衡,堆栈空间相对有限,所以我宁愿使用非递归函数。取而代之的是参考返回一个指针,将维持一个指针的指针当前节点,而不是一个指向节点:

Node** InternFind(int key) { 
    Node** n = &this->root; 
    while (*n && (*n)->key != key) { 
     n = &(key < (*n)->key? (*n)->left: (*n)->right); 
    } 
    return n; 
} 

的代码是未经测试,可能不完全正确。一旦你得到了指针品特,但是,你可以更新它无需处理,其中来自传来:

Node** r = InternFind(key); 
if (*r) { 
    Remove(*r); 
    return true; 
} 
else { 
    return false; 
} 

虽然我不知道什么是“如果Delete()火”的意思,我会想你对于同一个指针p重复使用delete p有问题。在访问过时的节点之前,代码很可能会出错。

+0

'r'实际上是'Node *&r',所以正确改变它会改变传入的参数。 Justin发现了真正的问题:调用Remove()后,父指针没有在父对象中更新。 –

+0

@j_random_hacker:感谢downvote,但考虑到'r'被定义为Node * r = Find(key,root);'当使用'Remove(r);'时它作为参考被传递的事实''不'真的很有帮助。无可否认,定义它的函数是'RemoveNode()'而不是'Remove()',但是(我在手机上编辑了答案,使得难以跟踪确切的细节)。重点是:如果传递了正确的引用(例如,通过将指针定位到指向节点的指针并将其解除引用),则会更新父指针! –

+0

我明白你的意思了。另一种方式(相当于你的'InternFind()'我认为)只是将Find()的返回类型改为'Node *&' - 引用和指针一样好。 (它看起来像OP可能一直在做这样的事情,对于'Find()')有其他无法解释的'Node *&r'参数。如果您在答案中澄清了参考文献的内容,我会+1。 –