Während ich versuchte, einen Fehler in einer Bibliothek zu beheben, suchte ich erfolglos nach Artikeln über das Auffinden von Unterbereichen auf roten und schwarzen Bäumen. Ich überlege mir eine Lösung mit Reißverschlüssen und etwas ähnlichem wie beim normalen Anhängen von Löschalgorithmen für unveränderliche Datenstrukturen, frage mich jedoch immer noch, ob es einen besseren Ansatz gibt, den ich nicht finden konnte, oder auch nur eine minimale Komplexitätsgrenze bei einer solchen Operation?
Um es klar auszudrücken, ich spreche von einem Algorithmus, der bei einem rot-schwarzen Baum und zwei Grenzen einen neuen rot-schwarzen Baum mit allen Elementen des ersten Baums erzeugt, die innerhalb dieser Grenzen liegen.
Eine Obergrenze für die Komplexität wäre natürlich die Komplexität, einen Baum zu durchqueren und den anderen durch Hinzufügen von Elementen zu konstruieren.
quelle
Antworten:
Diese Antwort kombiniert einige meiner Kommentare zu der Frage und erweitert sie.
Die Unterbereichsoperation für rot-schwarze Bäume kann im ungünstigsten Fall (log n) ausgeführt werden, wobei n die Anzahl der Elemente im ursprünglichen Baum ist. Da der resultierende Baum einige Knoten mit dem ursprünglichen Baum gemeinsam hat, ist dieser Ansatz nur geeignet, wenn Bäume unveränderlich sind (oder Bäume veränderlich sind, der ursprüngliche Baum jedoch nicht mehr benötigt wird).
Beachten Sie zunächst, dass die Unterbereichsoperation durch zwei Teiloperationen implementiert werden kann. Hier nimmt die Aufteilungsoperation einen rot-schwarzen Baum T und einen Schlüssel x und erzeugt zwei Bäume L und R, so dass L aus allen Elementen von T kleiner als x und R aus den Elementen von T größer als x besteht. Daher ist es unser Ziel, die Aufteilungsoperation für rot-schwarze Bäume im ungünstigsten Fall (log n) zu implementieren.
Wie führen wir die Aufteilungsoperation für rot-schwarze Bäume in der Zeit O (log n) durch? Nun, es stellte sich heraus, dass es eine bekannte Methode gab. (Ich wusste es nicht, aber ich bin kein Experte für Datenstrukturen.) Betrachten Sie die Verknüpfungsoperation , bei der zwei Bäume L und R so verwendet werden, dass jeder Wert in L kleiner als jeder Wert in R ist und ein Baum erzeugt wird, der aus allen besteht Werte in L und R. Die Verknüpfungsoperation kann in der ungünstigsten Zeit O (| r L - r R | +1) implementiert werden , wobei r L und r Rsind die Ränge von L bzw. R (dh die Anzahl der schwarzen Knoten auf dem Pfad von der Wurzel zu jedem Blatt). Die Aufteilungsoperation kann unter Verwendung der O-Zeiten (log n) der Verknüpfungsoperation implementiert werden, und die Gesamtzeit im ungünstigsten Fall ist unter Berücksichtigung einer Teleskopsumme immer noch O (log n).
In den Abschnitten 4.1 und 4.2 eines Buches [Tar83] von Tarjan wird beschrieben, wie die Verknüpfungs- und die Aufteilungsoperationen für rot-schwarze Bäume in der ungünstigsten Zeit O (log n) implementiert werden. Diese Implementierungen zerstören Originalbäume, aber es ist einfach, sie in unveränderliche, funktionale Implementierungen zu konvertieren, indem Knoten kopiert werden, anstatt sie zu ändern.
Als Randnotiz bieten das Set- und das Map-Modul von Objective Caml die Aufteilungsoperation sowie andere Standardoperationen für (unveränderliche) ausgeglichene binäre Suchbäume. Obwohl sie keine rot-schwarzen Bäume verwenden (sie verwenden ausgeglichene binäre Suchbäume mit der Einschränkung, dass sich die linke und die rechte Höhe um höchstens 2 unterscheiden), kann es auch nützlich sein, ihre Implementierungen zu betrachten. Hier ist die Implementierung des Set-Moduls .
Verweise
[Tar83] Robert Endre Tarjan. Datenstrukturen und Netzwerkalgorithmen . Band 44 der CBMS-NSF-Regionalkonferenzreihe für Angewandte Mathematik , SIAM, 1983.
quelle
Die Lösung ist, keine rot-schwarzen Bäume zu verwenden. In Splay-Bäumen und AVL-Bäumen ist der Code zum Teilen und Verbinden sehr einfach. Ich verweise Sie auf die folgenden URLs mit Java-Code für Splay-Bäume und AVL-Bäume, die dies unterstützen. Gehen Sie zur folgenden URL und überprüfen Sie Set.java (avl trees) und SplayTree.java (splay trees).
ftp://ftp.cs.cmu.edu/usr/ftp/usr/sleator/splaying/
--- Danny Sleator
quelle
O(n)
? Ich habe nicht gefragt, welche Art von Bäumen einfache Implementierungen von Unterbereichen aufweisen, da dies kein Problem darstellt. Diese Antwort ist zwar gut gemeint, aber nicht thematisch und für das vorliegende Problem unbrauchbar.(Dies soll ein Kommentar sein, aber ich bin zu neu, um einen Kommentar zu hinterlassen.)
Ich möchte lediglich darauf hinweisen, dass Sie möglicherweise auch an der Operation "Ausschneiden" interessiert sind, bei der der Unterbereich als neuer Baum und der Eingabebaum ohne Unterbereich als anderer zurückgegeben werden. Sie müssen jedoch die Kontrolle über die zugrunde liegende Darstellung des Baums haben, da die bekannte Methode auf Ebenenverknüpfungen beruht. Die Exzision verläuft zeitlogarithmisch zur Größe des kleineren Baumes, wenn auch im amortisierten Sinne ("amortisiert" ist iirc, weil ich keinen Zugang mehr zum Papier habe).
K. Hoffman, K. Mehlhorn, P. Rosenstiehl und RE Tarjan, Sorting Jordan Sequenzen in linearer Zeit mit Level Linked Search Trees, Information and Control, 68 (1986), 170-184
PS Das obige Zitat stammt aus Seidels Aufsatz. Treaps unterstützen auch die Exzision.
quelle
Ich habe die Details nicht ausgearbeitet, daher bin ich mir nicht sicher, wie sich die zusätzliche Buchhaltung auf die Laufzeit auswirkt.
quelle
O(logn)
, mit der ich das temporäre Array vermeiden könnte.