2012-02-17 144 views
1

我一直在爲大型項目開發簡單的二叉搜索樹。我理解二叉搜索樹的概念,並且在C++中執行語法時遇到了麻煩。我故意不使用boost的樹形容器。我的代碼樹如下。指針錯誤

struct Tree{ 
int nodeValue; 
Tree *nodeChild1; 
Tree *nodeChild2; 
Tree(int userProvidedValue){ 
    nodeValue = userProvidedValue; 
    nodeChild1 = NULL; 
    nodeChild2 = NULL; 
} 
static void placeValue(Tree &parent, int value); 
static Tree findValue(Tree parent, int value); 
static void crawl(Tree parent); 
~Tree(){ 

    delete nodeChild1; 
    delete nodeChild2; 
} 
}; 

void Tree::placeValue(Tree &parent, int value){ 
Tree node = Tree(value); 
cout<<"made node"<<endl; 
if(value>parent.nodeValue){ 
    cout<<"eval node child 2"<<endl; 
    if(parent.nodeChild2 ==NULL){ 
     cout<<"reaching this"; 
     parent.nodeChild2 = &node; 
    } 
    else{ 
     placeValue(*parent.nodeChild2, value); 
    } 
} 
if(value<=parent.nodeValue){ 
    cout<<"eval node child 1"<<endl; 
    if(!parent.nodeChild1){ 
       cout<<"assigning"<<endl; 
       parent.nodeChild1 = &node; 
    } 
      else{ 
         placeValue(*parent.nodeChild1, value); 
      } 
     } 
} 

然而,每當我構建一個樹Tree parent = Tree(5)然後另一個節點添加到它與Tree::placeValue(parent, 4)它編譯罰款,但彈出一個消息告訴我的EXE已崩潰。

任何人都可以請幫我理解這個崩潰來自哪裏?提前致謝。

代碼通過樹爬看起來是這樣的:

void Tree::crawl(Tree parent){ 
cout<<parent.nodeValue<<endl; 
if(NULL!=parent.nodeChild1){ 
    crawl(*parent.nodeChild1); 
} 
if(NULL!=parent.nodeChild2){ 
    crawl(*parent.nodeChild2); 
} 
} 

獎金問題:當樹::爬網需要樹&父的說法,而不是樹父的運行良好。但是,如果沒有&但它會失敗。任何人都可以解釋爲什麼這樣嗎?

回答

3

你必須在堆上分配樹(S)。

Tree node = Tree(value); 

在這裏你正在堆棧上分配一棵樹。這個變量的地址將在超出範圍後處理。爲了給它分配在堆中,只要使用new運算符:

Tree *node = new Tree(value); 

然後將其指定爲父母的孩子:

parent.nodeChild2 = node; 

關於樹::抓取錯誤,它是基於相同的錯誤。您繼續在堆棧中分配樹,因此,一旦它超出了作用域的調用,就會刪除(ing)nodeChild1和nodeChild2。您應該通過使用指針或始終使用引用來管理這些類型的結構,以便在函數結束時不調用樹的析構函數。因此:

void Tree::crawl(const Tree &parent){ 
    cout<<parent.nodeValue<<endl; 
    if(NULL!=parent.nodeChild1){ 
     crawl(*parent.nodeChild1); 
    } 
    if(NULL!=parent.nodeChild2){ 
     crawl(*parent.nodeChild2); 
    } 
} 

這應該這樣做。請記住,做同樣的樹:: findValue,你應該使用這個簽名是功能:

static Tree findValue(const Tree &parent, int value); 
+0

謝謝你的這個作品,但是現在當調用Tree :: crawl時會發生同樣的事情,程序編譯就會崩潰。你能想到一個理由嗎? – jozefg 2012-02-17 17:48:54

+0

如果你沒有發佈Tree :: crawl代碼,我不能幫你:D – mfontanini 2012-02-17 17:52:52

+0

哦,真的嗎?抱歉!我將張貼。 – jozefg 2012-02-17 17:57:22

3

您在堆棧中分配包含新值的Tree()實例,即Tree node = Tree(value);。當函數調用返回時,該實例將被銷燬,因此當您稍後嘗試訪問它時,程序會崩潰。

而且,你的析構函數調用它的兩個孩子delete,那麼想必你應該在堆上分配的Tree實例來解決您的問題:Tree* node = new Tree(value);

+0

+1爲'new' /'delete'對稱。 – David 2012-02-17 17:44:51

+0

謝謝,你會認爲考慮到我寫了析構函數,我會發現錯誤,但是啊。 – jozefg 2012-02-17 17:55:38

0
Tree node = Tree(value); 

node有它在聲明的程序塊的範圍將退出後自動deleled。出Tree::placeValue。當你得到指針時(parent.nodeChild2 = &node;),它會在退出後指向任何東西,並試圖解引用它會導致未定義的行爲。像這樣動態創建它:

Tree * node = new Tree(value);