Stackoverflow-Ausnahme, wenn BST durchqueren

stimmen
4

Ich habe einen Link-basierten BST (binärer Suchbaum) in C ++ implementiert für ein meine Aufgabe. Ich habe meine ganze Klasse geschrieben und alles funktioniert gut, aber meine Aufgabe fragt mich die Laufzeiten planen für:

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

Das ist in Ordnung, kann ich die Zahlen einfügen , aber es fragt mich auch anrufen FindHeight()und CountLeaves()Methoden auf dem Baum. Mein Problem ist , dass ich die beiden Funktionen haben implementiert recursion. Da habe ich eine so große Liste von Zahlen Ich erhalte eine immer stackoverflowAusnahme.

Hier ist meine Klassendefinition:

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 () Umsetzung

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 () -Implementierung

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

Ich habe versucht, zu denken, wie ich die beiden Methoden ohne Rekursion implementieren kann, aber ich bin völlig ratlos. Wer irgendwelche Ideen?

Veröffentlicht am 10/11/2011 um 00:52
quelle vom benutzer
In anderen Sprachen...                            


5 antworten

stimmen
1

Um die Blätter ohne Rekursion zu zählen, verwenden Sie das Konzept eines Iterators wie die STL für die zugrundeliegenden RB-Baum verwendet std::setund std::map... Erstellen Sie ein begin()und end()Funktion für Sie Baum, der die geordnete ersten und letzten Teilnehmer (in diesem Fall indentifies die linke -Die meisten Knoten und dann wird der am weitesten rechts liegenden Knoten). Dann erstellen Sie eine Funktion namens

BinarySearchTreeNode* increment(const BinarySearchTreeNode* current_node)

daß für einen gegebenen current_node, einen Zeiger auf den nächsten Knoten in dem Baum zurück. Denken Sie daran , für diese Umsetzung zu arbeiten, werden Sie einen zusätzlichen benötigen parentZeiger in Ihrer nodeArt in der Iteration Prozess zu unterstützen.

Ihr Algorithmus für increment()würde in etwa wie folgt aussehen:

  1. Überprüfen Sie, ob es ein Recht-Kind auf den aktuellen Knoten ist.
  2. Wenn es ein Recht-Kind ist, verwenden Sie eine while-Schleife, die den am weitesten links stehenden Knoten des rechten Teilbaumes zu finden. Dies wird der „nächste“ Knoten sein. Ansonsten geht # Schritt 3 fort.
  3. Wenn es kein rechts Kind auf dem aktuellen Knoten ist, dann prüfen Sie, ob der aktuelle Knoten das linke Kind seines Elternknotens ist.
  4. Wenn der Schritt # 3 wahr ist, dann ist der „nächste“ Knoten ist der übergeordnete Knoten, so dass Sie an dieser Stelle zu stoppen, sonst den nächsten Schritt gehen.
  5. Wenn der Schritt # 3 falsch war, dann der aktuelle Knoten das rechte Kind der Eltern. So müssen Sie zum nächsten übergeordneten Knoten bewegen zu halten, während einer Schleife, bis Sie über einen Knoten kommen, dass ein links Kind seines Elternknotens ist. Die Eltern dieser linken Kindknoten wird dann die „next“ Knoten, und Sie können stoppen.
  6. Schließlich, wenn der Schritt # 5 zurück in das Wurzel, dann der aktuelle Knoten der letzte Knoten in dem Baum, und der Iterator hat das Ende des Baumes erreicht.

Schließlich finden Sie eine brauchen bool leaf(const BinarySearchTreeNode* current_node)Funktion, ob ein gegebener Knoten testen ein Blattknoten ist. Damit Sie Zählerfunktion kann einfach wenn der Baum durchlaufen und alle Blattknoten finden, um eine endgültige Zählung zurückkehrt , sobald es fertig ist.

Wenn Sie die maximale Tiefe eines unausgeglichenen Baum ohne Rekursion messen wollen, werden Sie, in Ihrem Stammbaum der insert()Funktion benötigen Spur der Tiefe zu halten , dass ein Knoten an eingefügt wurde. Dies kann einfach eine Variable in Ihrem sein nodeTyp, der gesetzt wird , wenn der Knoten in den Baum eingefügt wird. Sie können dann durch die drei, durchlaufen und die maximale Tiefe eines Blattknotens finden.

BTW, ist die Komplexität dieser Methode leider gehen O (N) ... bei weitem nicht so schön wie O (log N) sein.

Beantwortet am 10/11/2011 um 01:01
quelle vom benutzer

stimmen
3

Rekursion auf einem Baum mit 100.000 Knoten sollte kein Problem sein , wenn es ausgewogen ist. Die Tiefe würde nur vielleicht 17 sein, die sehr viel Stack nicht gezeigt in den Implementierungen verwenden würden. (log2(100,000) = 16.61). So scheint es , dass vielleicht der Code, der den Baum baut balanciert es nicht richtig.

Beantwortet am 10/11/2011 um 01:02
quelle vom benutzer

stimmen
1

sein können, müssen Sie diese berechnen, während des Einsatzes zu tun. Lagern Sie die Höhen von Knoten, dh eine ganze Zahl addieren Feld wie in Höhe der Node-Objekt. Auch haben Zähler Höhe und Blätter für den Baum. Wenn Sie einen Knoten einzufügen, wenn seine Eltern ist (war) ein Blatt, Veränderung der Blattzahl tut, aber wenn nicht, Blattzahl um 1. Auch die Höhe des neuen Knotens ist in der Höhe des Elternteils + 1, also zu erhöhen, wenn diese größer ist als die aktuelle Höhe des Baumes, aktualisieren sie es dann. Es ist ein Hausaufgaben, so werde nicht ich Hilfe mit dem eigentlichen Code

Beantwortet am 10/11/2011 um 01:05
quelle vom benutzer

stimmen
2

Ich fand diese Seite sehr aufschlussreich , weil es über die Mechanik spricht eine Funktion der Umwandlung , die Rekursion verwendet man die Iteration verwendet.

Es hat Beispiele und zeigt Code.

Beantwortet am 10/11/2011 um 01:06
quelle vom benutzer

stimmen
1

Balancieren Sie Ihren Baum gelegentlich. Wenn Ihr Baum auf Stackoverflow FindHeight () bekommen, das bedeutet , dass Ihr Baum ist Art und Weise unausgewogen. Wenn der Baum ausgeglichen ist , sollte es nur eine Tiefe von 100000 Elementen etwa 20 Knoten hat.

Die einfachste (aber ziemlich langsam) Art und Weise der Neugewichtung unausgeglichen Binärbaum ist ein Array von zuzuteilen TItemgroß genug , um alle Daten in den Baum zu halten, werden alle Ihre Daten in es in sortierter Reihenfolge einfügen und löschen alle der Knoten . Dann wieder aufzubauen , den Baum aus dem Array rekursiv. Die Wurzel ist der Knoten in der Mitte. root->leftdie Mitte der linken Hälfte ist, root->rightist die Mitte der rechten Hälfte. Wiederholen Sie rekursiv. Dies ist die einfachste Art und Weise neu zu gewichten, aber es ist slowish und nimmt viel Speicher vorübergehend. Auf der anderen Seite, können Sie dies tun müssen, nur , wenn Sie erkennen , dass der Baum ist sehr unausgeglichen, (Tiefe auf dem Einsatz mehr als 100).

Die andere (bessere) Option ist bei Einfügungen zu balancieren. Die intuitive Art und Weise, dies zu tun ist, um zu verfolgen, wie viele Knoten unterhalb des aktuellen Knotens sind. Wenn das richtige Kind mehr als doppelt so viele „Kind“ Knoten als linke Kind hat, „drehen“ links. Und umgekehrt. Es gibt instrcutions, wie Baum alle über das Internet zu tun dreht. Dies macht Einsätze etwas langsamer, aber dann haben Sie nicht occassional massive Stände, die die erste Option erstellt. Auf der anderen Seite, müssen Sie ständig alle „Kinder“ zählt aktualisieren, wie Sie die dreht tun, was nicht trivial ist.

Beantwortet am 10/11/2011 um 01:08
quelle vom benutzer

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