Ich lerne Haskell und mache als Übung binäre Bäume. Nachdem ich einen regulären Binärbaum erstellt habe, möchte ich ihn so anpassen, dass er sich selbst ausbalanciert. So:
- Welches ist am effizientesten?
- Welches ist am einfachsten zu implementieren?
- Welches wird am häufigsten verwendet?
Aber entscheidend, welches empfehlen Sie?
Ich nehme an, das gehört hierher, weil es offen für Diskussionen ist.
haskell
functional-programming
data-structures
binary-tree
dan_waterworth
quelle
quelle
Antworten:
Ich würde empfehlen, mit einem Rot-Schwarz-Baum oder einem AVL-Baum zu beginnen .
Der rot-schwarze Baum kann schneller eingefügt werden, der AVL-Baum hat jedoch eine leichte Kante für die Suche. Der AVL-Baum ist wahrscheinlich ein bisschen einfacher zu implementieren, aber nicht so sehr auf der Grundlage meiner eigenen Erfahrung.
Der AVL-Baum stellt sicher, dass der Baum nach jedem Einfügen oder Löschen ausgeglichen wird (kein Unterbaum hat einen Ausgleichsfaktor von mehr als 1 / -1, während der Rot-Schwarz-Baum sicherstellt, dass der Baum jederzeit angemessen ausgeglichen ist.
quelle
Ich würde eine Alternative in Betracht ziehen, wenn Sie mit randomisierten Datenstrukturen zurechtkommen: Listen überspringen .
Aus einer übergeordneten Sicht handelt es sich um eine Baumstruktur, mit der Ausnahme, dass sie nicht als Baum, sondern als Liste mit mehreren Verknüpfungsebenen implementiert ist.
Sie erhalten O (log N) Einfügungen / Suchen / Löschen und müssen sich nicht mit all diesen kniffligen Fällen des Neuausgleichs befassen.
Ich habe noch nie darüber nachgedacht, sie in einer funktionalen Sprache zu implementieren, und die Wikipedia-Seite zeigt keine an, so dass es möglicherweise nicht einfach ist (wegen Unveränderlichkeit).
quelle
Wenn Sie mit einer relativ einfachen Struktur beginnen möchten (sowohl AVL-Bäume als auch rot-schwarze Bäume sind fummelig), ist eine Option ein Treap - benannt als eine Kombination aus "Baum" und "Haufen".
Jeder Knoten erhält einen "Prioritäts" -Wert, der beim Erstellen des Knotens häufig zufällig zugewiesen wird. Knoten werden in der Baumstruktur so positioniert, dass die Schlüsselreihenfolge und die haufenartige Reihenfolge der Prioritätswerte eingehalten wird. Heap-ähnliche Reihenfolge bedeutet, dass beide Kinder eines Elternteils niedrigere Prioritäten als das Elternteil haben.
BEARBEITEN wurde "innerhalb der Schlüsselwerte" oben gelöscht - die Priorität und die Schlüsselreihenfolge gelten zusammen, sodass die Priorität auch für eindeutige Schlüssel von Bedeutung ist.
Es ist eine interessante Kombination. Wenn Schlüssel eindeutig und Prioritäten eindeutig sind, gibt es eine eindeutige Baumstruktur für jede Gruppe von Knoten. Trotzdem sind Einfügungen und Löschungen effizient. Streng genommen kann der Baum bis zu einem Punkt aus dem Gleichgewicht gebracht werden, an dem es sich tatsächlich um eine verknüpfte Liste handelt. Dies ist jedoch äußerst unwahrscheinlich (wie bei Standard-Binärbäumen), auch in normalen Fällen, wenn Schlüssel in der richtigen Reihenfolge eingefügt werden (im Gegensatz zu Standard-Binärbäumen).
quelle
Vage und schwer zu beantworten. Die Komplexität der Berechnungen ist klar definiert. Wenn Sie das mit Effizienz meinen, gibt es keine wirkliche Debatte. In der Tat kommen alle guten Algorithmen mit Beweisen und Komplexitätsfaktoren.
Wenn Sie "Laufzeit" oder "Speichernutzung" meinen, müssen Sie die tatsächlichen Implementierungen vergleichen. Dann spielen Sprache, Laufzeit, Betriebssystem und andere Faktoren eine Rolle, die die Beantwortung der Frage erschweren.
Vage und schwer zu beantworten. Einige Algorithmen erscheinen Ihnen vielleicht komplex, aber für mich trivial.
Vage und schwer zu beantworten. Zuerst gibt es die "von wem?" Teil davon? Nur Haskell? Was ist mit C oder C ++? Zweitens gibt es ein proprietäres Softwareproblem, bei dem wir keinen Zugriff auf die Quelle haben, um eine Umfrage durchzuführen.
Richtig. Da Ihre anderen Kriterien nicht sehr hilfreich sind, ist dies alles, was Sie bekommen werden.
Sie können Quellcode für eine große Anzahl von Baumalgorithmen erhalten. Wenn Sie etwas lernen möchten, können Sie einfach jeden implementieren, den Sie finden können. Sammeln Sie einfach alle Algorithmen, die Sie finden, anstatt nach einer "Empfehlung" zu fragen.
Hier ist die Liste:
http://en.wikipedia.org/wiki/Self-balancing_binary_search_tree
Es sind sechs populäre definiert. Beginnen Sie mit denen.
quelle
Wenn Sie sich für Splay-Bäume interessieren, gibt es eine einfachere Version von denen, von denen ich glaube, dass sie zuerst in einem Artikel von Allen und Munroe beschrieben wurden. Es bietet nicht die gleichen Leistungsgarantien, vermeidet jedoch Komplikationen beim Umgang mit dem "Zick-Zack" -Umwuchten im Vergleich zum "Zick-Zack" -Umwuchten.
Grundsätzlich wird bei der Suche (einschließlich der Suche nach einer Einfügemarke oder einem zu löschenden Knoten) der gefundene Knoten von unten nach oben direkt zur Wurzel gedreht (z. B. wenn eine rekursive Suchfunktion beendet wird). Bei jedem Schritt wählen Sie eine einzelne Links- oder Rechtsrotation aus, je nachdem, ob das Kind, das Sie einen weiteren Schritt zur Wurzel hin hochziehen möchten, das rechte Kind oder das linke Kind war (wenn ich mich richtig an meine Rotationsrichtungen erinnere, ist das jeweils).
Wie bei Splay-Bäumen ist die Idee, dass sich zuletzt aufgerufene Objekte immer in der Nähe der Wurzel des Baums befinden und so schnell wieder zugänglich sind. Diese Allen-Munroe-Stammbäume (wie ich sie nenne - sie kennen den offiziellen Namen nicht) sind zwar einfacher, haben aber nicht die gleiche Garantie für die Leistung, die sich amortisiert.
Eine Sache - da diese Datenstruktur per Definition auch für Suchoperationen mutiert, müsste sie wahrscheinlich monadisch implementiert werden. IOW ist es vielleicht nicht gut für die funktionale Programmierung.
quelle
Ein sehr einfacher ausgeglichener Baum ist ein AA-Baum . Die Invariante ist einfacher und damit einfacher zu implementieren. Aufgrund seiner Einfachheit ist seine Leistung immer noch gut.
Als erweiterte Übung können Sie versuchen, mit GADTs eine der Varianten von ausgeglichenen Bäumen zu implementieren, deren Invariante vom Typsystemtyp erzwungen wird.
quelle