2012-02-17 4 views
1

J'ai travaillé sur un simple arbre de recherche binaire pour un projet plus important. Je comprends le concept d'un arbre de recherche binaire et j'ai simplement des problèmes avec la syntaxe de l'implémentation en C++. Je n'utilise délibérément pas de conteneurs d'arbre boost. Mon code pour l'arbre est le suivant.Erreurs avec des pointeurs

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); 
      } 
     } 
} 

Cependant chaque fois que je construis un arbre avec Tree parent = Tree(5) puis ajouter un autre nœud avec Tree::placeValue(parent, 4) il compile bien, mais un message apparaît me disant que l'exe est tombé en panne.

Quelqu'un peut-il m'aider s'il vous plaît à comprendre d'où vient ce plantage? Merci d'avance.

Le code de ramper à travers l'arbre ressemble à ceci:

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

Bonus Question: Quand l'arbre :: rampent prend l'argument de parent Arbre & au lieu de parent arbre, il fonctionne très bien. Cependant, sans le &, il échoue. Quelqu'un peut-il s'il vous plaît expliquer pourquoi c'est ainsi?

Répondre

3

Vous devez allouer Arbre (s) sur le tas.

Tree node = Tree(value); 

Ici, vous affectez un arbre sur la pile. L'adresse de cette variable sera éliminée après sa sortie de la portée. Afin de répartir sur le tas, il suffit d'utiliser le nouvel opérateur:

Tree *node = new Tree(value); 

puis attribuez-lui comme un enfant du parent:

parent.nodeChild2 = node; 

En ce qui concerne l'erreur d'arbre :: crawl, il est basé sur la même erreur. Vous continuez à allouer Tree (s) sur la pile, donc une fois qu'il est hors de portée son destructeur est appelé, supprimer (ing) nodeChild1 et nodeChild2. Vous devez gérer ces types de structures soit en utilisant des pointeurs, soit en utilisant toujours des références, de sorte que lorsqu'une fonction se termine, le destructeur de l'arbre n'est pas appelé. Par conséquent:

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

Cela devrait le faire. N'oubliez pas de faire la même chose sur l'arbre :: findValue, vous devez utiliser cette signature pour cette fonction:

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

Merci pour ce travail, cependant maintenant quand Tree :: crawl est appelé la même chose arrive, le programme compile puis se bloque. Pouvez-vous penser à une raison? – jozefg

+0

Si vous ne publiez pas le code Tree :: crawl, je ne peux pas vous aider: D – mfontanini

+0

Oh vraiment? Pardon! Je posterai ça. – jozefg

3

Vous allouez votre instance Tree() contenant la nouvelle valeur sur la pile, c'est-à-dire Tree node = Tree(value);. Lorsque l'appel de fonction revient, cette instance est détruite, donc lorsque vous essayez d'y accéder plus tard, le programme se bloque.

En outre, votre destructor appelle delete sur ses deux enfants, donc probablement vous devez attribuer l'instance Tree sur le tas pour résoudre votre problème: Tree* node = new Tree(value);

+0

+1 pour la nouvelle symétrie 'delete'. – David

+0

Merci, vous penseriez que vu que j'ai écrit le destructeur j'aurais attrapé l'erreur mais ah bien. – jozefg

0
Tree node = Tree(value); 

Le node a une portée du bloc du programme, il a été déclaré dans Il sera automatiquement deleled après la sortie. sur le Tree::placeValue. Lorsque vous obtenez le pointeur dessus (parent.nodeChild2 = &node;) il pointera vers rien après la sortie et tentera de le déréférencer provoquera un comportement indéfini. Créez-le dynamiquement comme ceci:

Tree * node = new Tree(value);