Binary Tree Rotation

stimmen
3

Ich arbeite einen AVL Suchbaum an der Umsetzung. Bisher habe ich die Codierung Teil beendet, und ich habe angefangen, es für Bugs zu testen. Ich fand heraus, dass meine Knoten Rotationsverfahren abgehört werden und um Gottes willen kann ich nicht verstehen, was das Problem ist.

Der Algorithmus funktioniert, wie es auf dem Papier soll aber, wenn es ... leckt Knoten Baum gut auf einer Maschine ausgeführt.

Dies ist die Methode verwendet , um einen Knoten nach links zu drehen: http://pastebin.com/mPHj29Af

bool avl_search_tree::avl_tree_node::rotate_left()
{
    if (_right_child != NULL) {
        avl_tree_node *new_root = _right_child;
 
        if (_parent != NULL) {
            if (_parent->_left_child == this) {
                _parent->_left_child = new_root;
            } else {
                _parent->_right_child = new_root;
            }
        }
 
        new_root->_parent = _parent;
        _parent = new_root;
 
        _right_child = new_root->_left_child;
        new_root->_left_child = this;
 
        if (_right_child != NULL) {
            _right_child->_parent = this;
        }
 
        //update heights
        update_height();
        new_root->update_height();
 
        return true;
    }
 
    return false;
}

In meinem Einfügemethode kommentierte ich die AVL Teil ausgleichend und stattdessen versuche ich gerade den neu eingefügten Knoten nach links zu drehen. Das Ergebnis für ganze Zahlen in aufsteigender Reihenfolge eingefügt: mein Baum enthält nur die anfängliche Wurzel (erste Knoten eingefügt) und alle anderen Knoten durchgesickert sind.

Jede Hilfe, um das Problem zu identifizieren ist sehr geschätzt, wie ich fange an, verrückt zu werden.

Für das Protokoll: Wenn ich den Baum keine Rotationen verwenden, nicht Knoten auslaufen und es funktioniert wie ein normalen unausgeglichen binärer Suchbaum (zum Einfügen und Lookup).

Edit: Aufgrund AJG85 Kommentars werde ich die Beobachtungen hinzu:

Ich fügte hinzu, printf Checks zum Destruktormethode von avl_search_tree :: avl_tree_node, die den Schlüsselwert gedruckt werden (in meinem Fall 32-Bit-Integer) vor Bereinigung und die insert-Methode des avl_search_tree, die den Schlüssel gedruckt werden nur eingefügt.

Dann in dem Einstiegspunkt des Programms zuweisen ich eine avl_search_tree auf dem Heap und fügen Sie Schlüssel, um es in aufsteigender Reihenfolge und dann löschen.

Mit AVL Balancing aktiviert bekomme ich die folgende Ausgabe im Terminal:

bool avl_search_tree::insert(const int&) : 1
bool avl_search_tree::insert(const int&) : 2
bool avl_search_tree::insert(const int&) : 3
bool avl_search_tree::insert(const int&) : 4
bool avl_search_tree::insert(const int&) : 5
bool avl_search_tree::insert(const int&) : 6
bool avl_search_tree::insert(const int&) : 7
bool avl_search_tree::insert(const int&) : 8
avl_search_tree::avl_tree_node::~avl_tree_node() : 1

Was bedeutet, daßalle Einfügungen waren erfolgreich, aber nur die Wurzel gelöscht wurde.

Mit dem AVL out kommentierte Balancing funktioniert es wie ein normaler binärer Suchbaum. Das Terminal ausgegeben wird:

bool avl_search_tree::insert(const int&) : 1
bool avl_search_tree::insert(const int&) : 2
bool avl_search_tree::insert(const int&) : 3
bool avl_search_tree::insert(const int&) : 4
bool avl_search_tree::insert(const int&) : 5
bool avl_search_tree::insert(const int&) : 6
bool avl_search_tree::insert(const int&) : 7
bool avl_search_tree::insert(const int&) : 8
avl_search_tree::avl_tree_node::~avl_tree_node() : 1
avl_search_tree::avl_tree_node::~avl_tree_node() : 2
avl_search_tree::avl_tree_node::~avl_tree_node() : 3
avl_search_tree::avl_tree_node::~avl_tree_node() : 4
avl_search_tree::avl_tree_node::~avl_tree_node() : 5
avl_search_tree::avl_tree_node::~avl_tree_node() : 6
avl_search_tree::avl_tree_node::~avl_tree_node() : 7
avl_search_tree::avl_tree_node::~avl_tree_node() : 8

Was bedeutet, dass alles richtig aufgeräumt wird.

Nun ... wie kam ich zu dem Schluss, dass die Rotationsverfahren sind die Themen? Unter dem AVL-Balancing Subroutine kommentiert habe ich eine Linie, die jeden neu eingefügten Knoten nach links dreht. Das Ergebnis? Das gleiche wie wenn das AVL Balancing Unterprogramm aktiviert wurde.

Und in Bezug auf die update_height () -Methode, ist es nicht die Struktur des Baumes verändert in keiner Weise.

Ich hoffe, das es zu klären.

Edit 2:

Um einige weitere Dinge zu klären, ist sein wie die avl_tree_node destructor implementiert:

avl_search_tree::avl_tree_node::~avl_tree_node()
{
    printf(%s : %d\n, __PRETTY_FUNCTION__, *_key);

    if (_left_child != NULL) {
        delete _left_child;
    }

    if (_right_child != NULL) {
        delete _right_child;
    }

    if (_key != NULL) {
        delete _key;
    }
}

_left_child und _right_child sind Zeiger Objekte auf dem Heap zugewiesen avl_tree_node.

Bearbeiten 3:

Dank AGJ85 der zweiten Kommentar fand ich das Problem. In meiner dreht Methode habe ich vergessen, dass ich eigentlich die Wurzel Zeiger auf die neue Wurzel des Baumes zu aktualisieren, wenn die Wurzel verschoben wurde.

Grundsätzlich ist die Wurzel des Baums zeigte immer auf den ersten Knoten eingefügt und ohne den Zeiger zu aktualisieren, wenn nötig, meine rotate Methoden würden die neue Baumwurzel auslaufen, die tatsächlich richtige konfiguriert wurde. :)

Danke AGJ85!

Veröffentlicht am 02/08/2011 um 18:19
quelle vom benutzer
In anderen Sprachen...                            


3 antworten

stimmen
2

EDIT - Verdammt - Ich habe nicht gesehen , dass das Problem schon (Antwort in Frage) gelöst. Vielleicht Dennoch gibt es einige nicht-Antwort Tipps in diesem Wert Bergungs.

Ich habe nicht sorgfältig geprüft, aber ich denke, du wirst falsch an dieser Linie ...

_right_child = new_root->_left_child;

und dass das Problem ist , dass Sie bereits überschrieben haben new_root->_left_childin der Linie ...

_parent->_left_child = new_root;

Was ich denke, Sie tun sollen, ist, am Anfang, hat einen Block von lokalen Definitionen wie ...

avl_tree_node *orig_parent      = _parent;
avl_tree_node *orig_this        = this;
avl_tree_node *orig_left_child  = _left_child;
avl_tree_node *orig_right_child = _right_child;

Dann nutzen Sie die orig_lokalen Variablen wie die Quellen für spätere Aufgaben. Das spart eine bestimmte Menge über Daten von mir Gedanken der verschiedenen Zeiger während der Drehung durchströmt. Die optimiser sollte etwa in diese loswerden jede redundante Arbeit sich Gedanken wert, und es gibt nicht viel von dieser sowieso.

Ein paar zusätzliche Punkte ...

Zunächst wird die C ++ (und C) Standards Reserve-Kennungen mit führenden Unterstrichen und mit doppelseitigem Unterstrichen. Es wird behauptet, dass Sie überraschen Interaktionen mit Standard- und Compiler gelieferten Bibliotheken erhalten können, wenn Sie nicht respektieren - ich denke, das für die Mitgliedskennungen Makro bezogen sein müßte, though. Nachgestellte Unterstrichen sind OK - ich neige dazu, um sie für die Schutztruppe geschaffen werden.

Eine übliche Konvention für Elementvariablen ist eine führende hinzuzufügen moder m_. Noch häufiger, vermutlich ist mit keinem besonderen Präfix oder gar Suffix.

Zweitens können Sie (oder auch nicht) finden es einfacher, AVL-Bäume zu implementieren, die Eltern Links nicht in dem Knoten gespeichert haben. Ich habe nicht AVL Bäume umgesetzt noch mich, aber ich habe einmal rot-schwarz Bäume implementieren. Eine Reihe von Algorithmen benötigen eine rekursive Suche als ersten Schritt schließen - Sie können nicht nur eine Standard-Suche, die den gefundenen Knoten erinnert aber verwirft den Weg nach unten zu diesem Knoten. Allerdings ist rekursive Implementierung nicht allzu schlecht, und es gibt wenige Zeiger zu jonglieren.

Schließlich ist ein allgemeiner Tipp - versuchen, „Trockenlauf“ ein Algorithmus wie diese kann man leicht stolpern , wenn Sie streng durch sie Schritt für Schritt arbeiten, und lassen Sie die Quellen der Informationen , die relevant sind (habe ich das schon geändert?) Bei jeder Schritt. Es ist sehr einfach , in die Gewohnheit, von einigen der Details für die Geschwindigkeit zu überspringen. Ein nützlicher maschinengestützten Trockenlauf ist , den Code Schritt- für -Schritt in einem Debugger, und sehen , ob die Ergebnisse bei jedem Schritt zustimmen mit dem Papier Trockenlauf laufen.

EDIT - eine Anmerkung - ich werde dies ein Hinweis nicht nennen , weil ich in diesem Zusammenhang nicht sicher bin. I in der Regel Datenstruktur Knoten mit einfachen Strukturen implementieren - keine Daten versteckt, nur wenige , wenn irgendwelche Mitgliederfunktionen. Die meiste Code wird getrennt von der Datenstruktur, die oft in einer „Werkzeug“ Klasse. Ich weiß , das die alte bricht „die Form zieht sich“ OOP Prinzip, aber IMO es funktioniert besser in der Praxis.

Beantwortet am 02/08/2011 um 20:34
quelle vom benutzer

stimmen
3

Dank AGJ85 der zweiten Kommentar fand ich das Problem. In meiner dreht Methode habe ich vergessen, dass ich eigentlich die Wurzel Zeiger auf die neue Wurzel des Baumes zu aktualisieren, wenn die Wurzel verschoben wurde.

Grundsätzlich ist die Wurzel des Baums zeigte immer auf den ersten Knoten eingefügt und ohne den Zeiger zu aktualisieren, wenn nötig, meine rotate Methoden würden die neue Baumwurzel auslaufen, die tatsächlich richtige konfiguriert wurde. :)

Beantwortet am 03/08/2011 um 10:03
quelle vom benutzer

stimmen
1

Ich sehe Sie den Fehler gefunden haben, das Sie in Ihrem Code suchen. (Wie Sie sagen, Sie waren nicht die Baumwurzel Zeiger auf die neue Wurzel zu aktualisieren, wenn die Wurzel geändert. Es ist ein allgemeines Paradigma für die Liste und Baum Einfügen / Methoden löschen einen Zeiger auf den Kopf der Liste oder Wurzel des Baumes zurückzukehren, und wenn Sie vergessen, dass Paradigma wird nicht den Fehler wieder machen.)

Auf einer höheren Ebene aus betrachtet, haben die Technik , die ich verwendet , um Probleme mit zu vermeiden AVL - Baum oder Rot-Schwarz - Baum - Code ist stattdessen ein verwenden AA - Baum , die ihnen ähnliche Leistung, O (n) Raum und O (log mit n) Zeit für Einfügen, löschen und suchen. Allerdings sind AA Bäume Code wesentlich einfacher.

Beantwortet am 04/08/2011 um 16:55
quelle vom benutzer

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