2013-10-29 95 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。 –