Gegeben seien zwei AVL - Bäume und , und ein Wert so dass , ist es einfach , eine neue AVL - Baum enthält , zu konstruieren , und die Werte in und in der Zeit , wobei die Höhe eines Baumes (solange Bäume ihre Höhe speichern).
Dies ist auch für rot-schwarze Bäume möglich, und ich gehe auch von vielen anderen Arten ausgewogener Bäume aus.
Ist dies für Treaps oder treapartige Datenstrukturen möglich? Was ist, wenn wir ?
erwartete Zeit. Wenn es einen Weg gibt , erwartet auszuführen O (1) auf treaps verbinden (oder Treap artigen Datenstrukturen) mit etwa gleicher Größe (oder Root - Priorität) Ich denke, es könnte möglich sein, einen Trick von Kaplan & Tarjan zu verwenden, bei dem die Stacheln gebootet werden, um Treaps (oder treapähnliche Datenstrukturen) mit doppelt logarithmischer Verknüpfung zu erstellen.
Antworten:
Nein, das ist mit normalen Treaps nicht möglich, wenn die Prioritäten zufällig sind.
Die genaue Behauptung, die ich machen werde, ist, dass eine solche Zusammenführung von zwei gleich großen Treaps mit zufälligen Prioritäten eine Aktualisierung von Zeigern in Erwartung erfordert .Θ ( logn )
Hier ist eine grobe Beweisskizze:
Berücksichtigen Sie die Anzahl der Zeiger, die Sie in der Erwartung ändern müssen, um die Operation auszuführen. Es ist einfacher, eine -Grenze zu beweisen , wenn wir nicht t r einfügen, sondern nur T 1 und T 2 zusammenführen . Betrachten Sie den rechten Rücken S 1 von T 1 und den linken Rücken S 2 von T 2 . Färbe die Elemente von S 1 rot und die von S 2 blau. Ordnung S 1 ∪ S 2Θ ( logn ) tr T1 T2 S1 T1 S2 T2 S1 S2 S1∪ S2 nach Priorität. Wir müssen jedes Mal einen Zeiger ändern, wenn sich die Farbe in dieser Reihenfolge ändert. Da beide Stacheln mit hoher Wahrscheinlichkeit die Größe haben und die Prioritäten zufällig sind, ist es nicht schwer zu erkennen, dass die Anzahl der Farbänderungen in der Sequenz auch Θ ( log n ) beträgt . Wir müssen also Θ ( log n ) Zeiger für die Zusammenführung aktualisieren (ohne t r hinzuzufügen ).Θ ( logn ) Θ ( logn ) Θ ( logn ) tr
Jetzt hilft es nicht viel, während des Zusammenführens hinzuzufügen . Die Anzahl der Zeigeränderungen kann in diesem Fall wie folgt niedriger sein: Reihenfolge S 1 ≤ S 2 ≤ { t r } nach Priorität. Löschen Sie alles, was in der Sequenz weniger als t r ist. Dann ist die Anzahl der Farbänderungen in der resultierenden Sequenz unsere Untergrenze. Da t r Zufalls Priorität hat, ist die erwartete Höhe des Teilbaums an ihn in der endgültigen Treap verwurzelten O ( 1 ) , so dass es nur über O ( 1 ) Knoten von S 1tr S1∪ S2∪ { tr} tr tr O ( 1 ) O ( 1 ) . mit niedrigerer Priorität als erwartet, so dass wir nur O ( 1 ) Zeigeränderungen in unserer unteren Schranke verloren haben, wennwir t r addierenS1∪ S2 O ( 1 ) tr
Nun, das heißt, es gibt wahrscheinlich eine Möglichkeit, eine "treap-ähnliche" Datenstruktur zu erhalten, die konstante erwartete Zeitverschmelzungen ermöglicht.
quelle
Update: Im Folgenden finden Sie ein Update zur Fehlerhaftigkeit dieses Join-Vorgangs
Hier ist eine sehr grobe Skizze einer möglichen Lösung:
Ich glaube, ich habe eine Lösung für dieses Problem mit einer Art zufällig ausgewogenem B + -Baum. Diese Bäume haben wie Treaps eine einzigartige Repräsentation. Im Gegensatz zu Treaps speichern sie einige Schlüssel mehrmals. Es könnte möglich sein, dies mit einem Trick aus Bent et al. "Biased Search Trees" zu beheben, bei dem jeder Schlüssel nur in der höchsten (dh der Wurzel nächstgelegenen) Ebene gespeichert wird, in der er erscheint.
Ein Baum für einen geordneten Satz eindeutiger Werte wird erstellt, indem zunächst jedem Wert ein Bitstrom zugeordnet wird, ähnlich wie jedem Wert in einem Treap eine Priorität zugeordnet wird. Jeder Knoten im Baum enthält sowohl einen Schlüssel als auch einen Bitstrom. Nicht-Blattknoten enthalten zusätzlich eine natürliche Zahl, die die Höhe des Baums angibt, der an diesem Knoten verwurzelt ist. Interne Knoten können eine beliebige Anzahl von Kindern ungleich Null haben. Wie bei B + -Bäumen ist jeder sich nicht selbst schneidende Pfad von der Wurzel zu einem Blatt gleich lang.
Jeder interne Knoten enthält (wie in B + -Bäumen) den größten Schlüssel k seiner Nachkommenblätter. Jedes enthält auch eine natürliche Zahl i , die die Höhe des Baums angibt, der bei v verwurzelt ist , und den Strom von Bits, die mit k ab dem i + 1- ten Bit verknüpft sind. Wenn jeder Schlüssel in dem Baum, der mit v verwurzelt ist, dasselbe erste Bit in seinem Bitstrom hat, ist jedes Kind von v ein Blatt und i ist 1 . Andernfalls sind die Kinder von v interne Knoten, von denen alle das gleiche i- te Bit in dem ihrem Schlüssel zugeordneten Bitstrom haben.v k ich v k i + 1 v v ich 1 v ich
Um einen Baum aus einer sortierten Liste von Schlüsseln mit zugeordneten Bitströmen zu erstellen, sammeln Sie zuerst die Schlüssel in zusammenhängenden Gruppen basierend auf dem ersten Bit in ihren Streams. Erstellen Sie für jede dieser Gruppen ein übergeordnetes Element mit dem Schlüssel und dem Bitstrom des größten Schlüssels in der Gruppe, aber ohne das erste Bit des Stroms. Führen Sie nun das gleiche Gruppierungsverfahren für die neuen Eltern durch, um Großeltern zu erstellen. Fahren Sie fort, bis nur noch ein Knoten übrig ist. Das ist die Wurzel des Baumes.
Die folgende Liste der Schlüssel und (Anfangs-) Bitströme wird durch den Baum darunter dargestellt. In den Bitstrom-Präfixen ist ein '.' bedeutet ein bisschen. Das heißt, jeder Bitstrom für den Schlüssel A mit einer 0 erzeugt an erster Stelle den gleichen Baum wie jeder andere, vorausgesetzt, kein Bitstrom eines anderen Schlüssels ist unterschiedlich.
Jedes Kind eines bestimmten internen Knotens hat an erster Stelle seines Bitstroms das gleiche Bit. Dies nennt man die "Farbe" des Elternteils - 0 ist rot, 1 ist grün. Das Kind hat einen "Geschmack", der vom ersten Bit seines Bitstroms abhängt - 0 ist Kirsche, 1 ist Minze. Blätter haben Aromen, aber keine Farbe. Per Definition kann ein Kirschknoten keinen grünen Elternknoten und ein Minzknoten keinen roten Elternknoten haben.
Um zwei Bäume gleicher Höhe zu verbinden, prüfen Sie zunächst, ob ihre Wurzeln die gleiche Farbe haben. Wenn ja, trennen Sie von der linken Wurzel das am weitesten rechts stehende Kind und von der rechten Wurzel das am weitesten links stehende Kind, und verbinden Sie diese beiden Bäume rekursiv. Das Ergebnis ist ein Baum mit der gleichen Höhe oder einer Höhe, da die Bäume den gleichen Geschmack haben (siehe unten). Wenn das Ergebnis des rekursiven Verbindens der beiden Bäume dieselbe Höhe hat wie die beiden abgetrennten Kinder, machen Sie es zum mittleren Kind einer Wurzel, wobei die verbleibenden Kinder der linken Wurzel davor und die verbleibenden Kinder der rechten Wurzel danach liegen. Wenn es um 1 größer ist, machen Sie seine Kinder zu den mittleren Kindern einer Wurzel mit den verbleibenden Kindern der linken Wurzel davor und den verbleibenden Kindern der rechten Wurzel danach. Wenn die Wurzeln unterschiedliche Farben haben, prüfen Sie, ob sie den gleichen Geschmack haben. Wenn sie es tun, Geben Sie ihnen ein neues übergeordnetes Element mit dem Schlüssel und dem Bitstrom der rechten Wurzel, wobei das erste Bit entfernt wird. Wenn dies nicht der Fall ist, geben Sie jeder Wurzel ein neues übergeordnetes Element mit dem Schlüssel und dem Bitstrom der alten Wurzel (wobei jedes erste Bit entfernt wird) und verbinden Sie diese Bäume dann rekursiv.Der von gemachte Baum
[a,b]
hat eine Höhe von 2, der von gemachte Baum[c,d]
hat eine Höhe von 2 und der von gemachte BaumjoinEqual (tree [a,b]) (tree [c,d])
hat eine Höhe von 3. Der von gemachte Baum[a,b,c,d]
hat jedoch eine Höhe von 5.Hier ist der Code, mit dem ich diesen Fehler gefunden habe .
quelle