Stackoverflow exception lors de la traversée BST

voix
4

Je mettre en œuvre un BST basée sur des liens (arbre binaire de recherche) en C ++ pour une de mes missions. Je l'ai écrit ma classe entière et tout fonctionne bien, mais ma mission me demande de tracer les temps d'exécution pour:

a.  A sorted list of 50000, 75000, and 100000 items
b.  A random list of 50000, 75000, and 100000 items

Très bien, je peux insérer les chiffres , mais il me demande aussi d'appeler la FindHeight()et CountLeaves()méthodes sur l'arbre. Mon problème est que je l' ai mis à exécution les deux fonctions à l' aide recursion. Depuis que j'ai une telle grande liste des numéros que je reçois obtenir une stackoverflowexception.

Voici ma définition de la classe:

template <class TItem>
class BinarySearchTree
{
public:
    struct BinarySearchTreeNode
    {
    public:
        TItem Data;
        BinarySearchTreeNode* LeftChild;
        BinarySearchTreeNode* RightChild;
    };

    BinarySearchTreeNode* RootNode;

    BinarySearchTree();
    ~BinarySearchTree();

    void InsertItem(TItem);

    void PrintTree();
    void PrintTree(BinarySearchTreeNode*);

    void DeleteTree();
    void DeleteTree(BinarySearchTreeNode*&);

    int CountLeaves();
    int CountLeaves(BinarySearchTreeNode*);

    int FindHeight();
    int FindHeight(BinarySearchTreeNode*);

    int SingleParents();
    int SingleParents(BinarySearchTreeNode*);

    TItem FindMin();
    TItem FindMin(BinarySearchTreeNode*);

    TItem FindMax();
    TItem FindMax(BinarySearchTreeNode*);
};

FindHeight () Mise en œuvre

template <class TItem>
int BinarySearchTree<TItem>::FindHeight()
{
    return FindHeight(RootNode);
}

template <class TItem>
int BinarySearchTree<TItem>::FindHeight(BinarySearchTreeNode* Node)
{
    if(Node == NULL)
        return 0;

    return 1 + max(FindHeight(Node->LeftChild), FindHeight(Node->RightChild));
}

CountLeaves () mise en œuvre

template <class TItem>
int BinarySearchTree<TItem>::CountLeaves()
{
    return CountLeaves(RootNode);
}

template <class TItem>
int BinarySearchTree<TItem>::CountLeaves(BinarySearchTreeNode* Node)
{
    if(Node == NULL)
        return 0;
    else if(Node->LeftChild == NULL && Node->RightChild == NULL)
        return 1;
    else
        return CountLeaves(Node->LeftChild) + CountLeaves(Node->RightChild);
}

J'ai essayé de penser à ce que je peux mettre en œuvre les deux méthodes sans récursion mais je suis complètement déconcerté. Quelqu'un at-il des idées?

Créé 10/11/2011 à 00:52
source utilisateur
Dans d'autres langues...                            


5 réponses

voix
1

Pour compter les feuilles sans récursion, utiliser le concept d'un iterator comme la STL utilise pour le RB-arbre sous-jacent std::setet std::map... Créer une begin()et end()fonction pour vous arbre qui indentifies le premier ordre et le dernier noeud (dans ce cas , la gauche noeud, puis le -La plupart le plus à droite nœud). Ensuite , créez une fonction appelée

BinarySearchTreeNode* increment(const BinarySearchTreeNode* current_node)

que , pour une donnée current_node, renvoie un pointeur vers le nœud suivant dans l'arbre. Gardez à l' esprit pour cette mise en œuvre au travail, vous aurez besoin d' un supplémentaire parentpointeur dans votre nodegenre à aider dans le processus d'itération.

Votre algorithme increment()ressemblerait à quelque chose comme ce qui suit:

  1. Vérifiez s'il y a un droit enfant au noeud courant.
  2. S'il y a un droit enfant, utilisez un certain temps en boucle pour trouver le nœud le plus à gauche de cette sous-arbre droit. Ce sera le noeud « suivant ». Sinon, passez à l'étape 3.
  3. S'il n'y a pas de droit enfant sur le nœud actuel, puis vérifiez si le noeud courant est le fils gauche de son nœud parent.
  4. Si l'étape 3 est vrai, le noeud « suivant » est le nœud parent, de sorte que vous pouvez arrêter à ce stade, sinon, passez à l'étape suivante.
  5. Si l'étape 3 était fausse, alors le noeud courant est le droit enfant du parent. Ainsi, vous devrez continuer à aller jusqu'au nœud parent suivant en utilisant une boucle while jusqu'à ce que vous tombez sur un noeud qui est un enfant gauche de son nœud parent. Le parent de ce nœud enfant gauche sera alors le noeud « suivant », et vous pouvez arrêter.
  6. Enfin, si l'étape 5 vous renvoie à la racine, le noeud courant est le dernier nœud dans l'arbre et le iterator a atteint la fin de l'arbre.

Enfin , vous aurez besoin d' une bool leaf(const BinarySearchTreeNode* current_node)fonction qui permettra de vérifier si un noeud donné est un nœud feuille. Ainsi , vous fonction compteur peut simplement itérer que l'arbre et trouver tous les nœuds feuilles, retournant un décompte final une fois qu'il est fait.

Si vous voulez mesurer la profondeur maximale d'un arbre non équilibré sans récursion, vous, dans votre arbre insert()de la fonction, le besoin de garder une trace de la profondeur qu'un noeud a été inséré à. Cela peut simplement être une variable dans votre nodetype qui est défini lorsque le noeud est inséré dans l'arbre. Vous pouvez ensuite parcourir les trois, et trouver la profondeur maximale d'un nœud de feuille.

BTW, la complexité de cette méthode va malheureusement être O (N) ... loin d'être aussi belle que O (log N).

Créé 10/11/2011 à 01:01
source utilisateur

voix
3

Récursivité sur un arbre avec 100.000 nœuds ne devrait pas être un problème si elle est équilibrée. La profondeur ne serait peut - être 17, ce qui ne serait pas utiliser la pile très bien dans les implémentations indiquées. (log2(100,000) = 16.61). Il semble donc que peut - être le code qui construit l'arbre ne soit pas en équilibre correctement.

Créé 10/11/2011 à 01:02
source utilisateur

voix
1

Peut-être que vous devez calculer ce tout en faisant l'insert. Conserver les hauteurs de noeuds, à savoir ajouter un champ entier comme la hauteur dans l'objet de nœud. Ont également la hauteur des compteurs et des feuilles pour l'arbre. Lorsque vous insérez un nœud, si son parent est (était) une feuille, le nombre de feuilles ne marche pas le changement, mais sinon, augmenter le nombre de feuilles par 1. De plus la hauteur du nouveau nœud est la hauteur du parent + 1, donc si cela est plus à la hauteur actuelle de l'arbre, mettre à jour il. C'est un travail à domicile, donc je wont aide avec le code réel

Créé 10/11/2011 à 01:05
source utilisateur

voix
2

J'ai trouvé cette page très instructive car elle parle de la mécanique de la conversion d' une fonction qui utilise la récursivité pour celui qui utilise l' itération.

Il a des exemples montrant code.

Créé 10/11/2011 à 01:06
source utilisateur

voix
1

L' équilibre de votre arbre de temps en temps. Si votre arbre devient stackoverflow sur FindHeight (), cela signifie que votre arbre est ainsi déséquilibrée. Si l'arbre est équilibré , il ne devrait avoir une profondeur d'environ 20 noeuds pour 100000 éléments.

Le plus facile (mais assez lent) façon de rééquilibrer l' arbre binaire non équilibré est d'allouer un tableau de TItemassez grand pour contenir toutes les données dans l'arborescence, insérez toutes vos données dans dans l' ordre de tri et supprimer tous les nœuds . Puis reconstruire l'arbre du tableau récursive. La racine est le noeud dans le milieu. root->leftest au milieu de la moitié gauche, root->rightest au milieu de la moitié droite. Répétez récursive. Ceci est la meilleure façon de rééquilibrer, mais il est slowish et prend beaucoup de mémoire temporaire. D'autre part, il suffit de le faire lorsque vous constatez que l'arbre est très déséquilibré, (profondeur sur insert est plus de 100).

L'autre option (mieux) est à l'équilibre lors des insertions. La façon la plus intuitive de le faire est de garder une trace de combien de nœuds sont sous le noeud courant. Si l'enfant a plus de droit deux fois plus de nœuds « enfants » comme l'enfant à gauche, « Rotate » à gauche. Et vice versa. Il y a instrcutions sur la façon de faire l'arbre tourne partout sur l'internet. Cela rend inserts un peu plus lent, mais vous n'avez pas des stalles massives occassional que la première option crée. D'autre part, vous devez mettre à jour en permanence tous les « enfants » compte que vous faites la rotation, ce qui est trivial.

Créé 10/11/2011 à 01:08
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more