2016-09-06 35 views
0

刪除我的孩子有這樣的結構:C++:二叉樹 - 從親代載體

#include <stddef.h> 
#include <vector> 

typedef int T; 
class tree; 

class node { 
    T info; 
    std::vector<node*> children; 
    friend class tree; 
public: 
    typedef std::vector<node*>::iterator iterator; 
    iterator begin() { 
     return children.begin(); 
    } 
    iterator end() { 
     return children.end(); 
    } 
    T get() { 
     return info; 
    } 
}; 

class tree { 
    node* r; 
    void del(node* v) { 
     if (v == NULL) return; 
     for (node::iterator it = v->begin(); it != v->end(); ++it)  
      del(*it); 
     delete v; 
    } 
public: 
    tree() : r(NULL) { } 
    node* add(T info, node* parent) { 
     node* v = new node; 
     v->info = info; 
     if (parent != NULL) parent->children.push_back(v); 
     else { 
      if (r != NULL) del(r); 
      r = v; 
     } 
     return v; 
    } 
node* add(T info) { 

     return add(info, NULL); 
    } 
    node* root() { return r; } 
    void remove(node* v) { 
     if (r == v) r = NULL; 
     else { /* remove v from the list of children of its parent */ } 
     del(v); 
    } 
}; 

我需要完成的功能從其父母的列表中刪除節點v卸下。爲了有效地這樣做,我會向節點類添加一個指向其父節點的指針,並相應地更新添加函數。 這是我的解決方案 我修改與增加功能:

node* add(T info, node* parent) { 
    node* v = new node; 
    v->info = info; 
    if (parent != NULL) { 
     parent->children.push_back(v); 
     v->parent=parent; } 
    else { 
     if (r != NULL) del(r); 
     r = v; 
     r->parent=null; 
      } 
    return v; 
} 

,我修改刪除功能:

void remove(node* v) { 
     if (r == v) r = NULL; 
     else { 
     v->parent->children.pop_back(v); 
     } 
     del(v); 
    } 

這是概念上是否正確?不幸的是,類vectorpop_back method不允許這種類型的參數,所以這會返回一個錯誤。 這是正確的還是應該使用其他實現?

對不起,我不是很熟悉C++。由於

回答

0

pop_back刪除Vector中的最後一個元素 - 無論它是...

試試這個:

std::vector<node*>::iterator entry = std::find(v->parent->begin(), v->parent->end(), v); 
if(entry != v->parent->end()) 
    v->parent->erase(entry); 

或更短:

auto entry = std::find(v->parent->begin(), v->parent->end(), v); 
/* ... */ 

變種會使用std ::刪除:

v->parent->erase(std::remove(v->parent->begin(), v->parent->end(), v), v->parent->end()); 

std::remove移除了給定範圍內的v的所有 OCCURENCES(假設它只有一個...)通過移動所有後續元件朝開始位置的適當數量(如果一個元件已被移除,一個位置,如果兩個元素,兩個位置......)並且將迭代器返回到仍然在使用中的最後一個之後的位置。但是,從這裏開始的元素仍然保留在向量(或列表或...)中,因此您必須刪除這些元素,這是由函數vector::erase的第二個變體完成的。概念:有一點對我來說很重要:如果父母爲空,則想要刪除根。但是,如果root擁有孩子本身呢?你會在del函數中遞歸地刪除它們嗎?你確定你真的想替換已經包含的整個樹嗎?可能最好是的孩子呢?

但是現在不要把它理解爲「你應該這樣做」 - 這只是一個推薦的想法 - 但我不知道你的要求,所以這取決於你自己決定......只有一個重要的事情:不要忘了刪除節點的孩子,如果你刪除它,否則你有內存泄漏...

除此之外,你的概念乍一看對我來說很好...

編輯:回答您的評論的問題:適當的析構函數應該是這樣的:

~node() 
{ 
    for(node* n : children) 
    { 
     delete n; 
    } 
} 

這會遞歸地刪除所有子節點的所有節點。所有你需要做的,以清除整棵樹是

delete r; 
r = nullptr; 

e。 g .:

void clear() 
{ 
    delete r; 
    r = nullptr; 
} 
~tree() 
{ 
    clear(); 
} 

我認爲這不是你的意圖,但是如果你的節點被插入到多個子載體中,你將陷入深重的麻煩!

因此,如果您計劃稍後重新租用節點,請記住從其父列表中刪除節點。如果你想保留一些子節點,當然你需要先把它們從樹中移出。

+0

謝謝,您的建議是正確的。這是一個練習,所以我必須尊重結構和實施。順便說一句,我會問,我怎樣才能使樹的解構器,以一種方式來刪除樹的所有節點? – rollotommasi

+0

@rollotommasi增加了一個析構函數給我的答案... – Aconcagua

+0

謝謝你。老實說,我不知道用於「for」指令的風格,這就是爲什麼我有點卡住。建立一個類的destroctor並不是一個好習慣,它銷燬那些沒有在那個類中聲明的項目,我想......這就是爲什麼在〜tree()中我們只刪除r,並且在〜node()中我們刪除所有節點...! @Aconcagua – rollotommasi

0

其實我做這樣的事情:

~tree() 
{ 
    for(node::iterator it=r->children.begin(); it!=r->children.end(); ++it) 
    { 
     (*it)->info=NULL; 
     node* tmp= new node; 
     tmp=(*it); 
     delete tmp; 
    } 
    r->info=NULL; 
    delete r; //Dealloco la memoria riservata ad r 
} 
+0

編輯你的答案,使其成爲代碼段而不是引文。你應該只粘貼與解決方案相關的代碼 - 輸出到std :: cout不是,在這種情況下,所以我刪除了它......但是,你有內存泄漏! – Aconcagua

+0

'node * tmp = new node;'創建一個新節點,然後'* it' *被複制*並且您再次刪除該副本;在對照中'* it'永遠不會被刪除;另外,你不考慮刪除孩子的孩子! – Aconcagua

+0

是的,我注意到它太晚了(哈哈)。順便說一句,如果我嘗試'刪除(*)),xcode返回錯誤!爲了刪除兒童的孩子,應該刪除只傳遞每個節點的孩子的del函數。所以我可以再次調用'del(* it)'並立即調用'delete(* it)'。 !我對嗎? – rollotommasi