Sie können einen AVL-Baum ohne Schlüssel oder ähnliches verwalten.
Es würde wie folgt funktionieren: Der Baum behält eine Reihenfolge auf den Knoten bei, wie es ein AVL-Baum normalerweise tut, aber anstatt dass der Schlüssel bestimmt, wo der Knoten "liegen" soll, gibt es keine Schlüssel, und Sie müssen die Knoten explizit "nach" einfügen "ein anderer Knoten (oder mit anderen Worten" zwischen "zwei Knoten), wobei" nach "bedeutet, dass er in der Reihenfolge des Durchlaufs des Baums nach ihm kommt. Der Baum behält somit die Reihenfolge für Sie auf natürliche Weise bei und würde sich aufgrund der eingebauten Rotationen der AVL auch ausgleichen. Dadurch wird alles automatisch gleichmäßig verteilt.
Einfügen
Zusätzlich zum regelmäßigen Einfügen in die Liste, wie in der Frage gezeigt, würden Sie einen separaten AVL-Baum pflegen. Das Einfügen in die Liste selbst erfolgt , da Sie die Knoten "before" und "after" haben.O(1)
Die Einfügezeit in den Baum beträgt , genau wie das Einfügen in einen AVL-Baum. Beim Einfügen wird ein Verweis auf den Knoten erstellt, nach dem Sie einfügen möchten, und Sie fügen den neuen Knoten einfach links vom linken Knoten des rechten untergeordneten Knotens ein. Dieser Ort ist "nächster" in der Reihenfolge des Baums (er ist der nächste in der Reihenfolge der Durchquerung). Führen Sie dann die typischen AVL-Rotationen aus, um den Baum neu auszugleichen. Sie können einen ähnlichen Vorgang für "Einfügen vor" ausführen. Dies ist hilfreich, wenn Sie etwas in den Anfang der Liste einfügen müssen und kein Knoten "vor" vorhanden ist.O(logn)
Fragen beantworten
Um Fragen zu zu beantworten , finden Sie einfach alle Vorfahren von und im Baum und analysieren die Position, an der die Vorfahren im Baum voneinander abweichen. derjenige, der nach "links" abweicht, ist der kleinere von beiden.(X<?Y)XY
Diese Prozedur benötigt Zeit, um den Baum zur Wurzel zu klettern und die Ahnenlisten zu erhalten. Es ist zwar wahr, dass dies langsamer als ein ganzzahliger Vergleich erscheint, aber die Wahrheit ist, dass es dasselbe ist; Nur dieser ganzzahlige Vergleich auf einer CPU wird durch eine große Konstante begrenzt, um sie . Wenn Sie diese Konstante überlaufen lassen, müssen Sie mehrere Ganzzahlen ( Ganzzahlen) beibehalten und dasselbe Vergleiche. Alternativ können Sie die Baumhöhe um einen konstanten Betrag "binden" und auf die gleiche Weise "betrügen" wie die Maschine mit ganzen Zahlen: Jetzt werden Abfragen als .O(logn)O(1)O(logn)O(logn)O(1)
Demonstration des Einfügevorgangs
Zur Demonstration können Sie einige Elemente mit ihrer Reihenfolge aus der Liste in die Frage einfügen:
Schritt 1
Beginnen Sie mitD
Liste:
Baum:
Schritt 2
Fügen Sie , .C∅<C<D
Liste:
Baum:
Beachten Sie, dass Sie explizit vor , nicht weil der Buchstabe C vor D steht, sondern weil in der Liste steht.CDC<D
Schritt 3
Fügen Sie , .A∅<A<C
Liste:
Baum:
AVL-Drehung:
Schritt 4
Fügen Sie , .A < B < CBA<B<C
Liste:
Baum:
Keine Rotationen notwendig.
Schritt 5
Fügen Sie ,D < E < ∅ED<E<∅
Liste:
Baum:
Schritt 6
Fügen Sie ,B < F < CFB<F<C
BBFB
Liste:
Baum:
AVL-Rotation:
Demonstration der Vergleichsoperation
A<?F
ancestors(A) = [C,B]
ancestors(F) = [C,B]
last_common_ancestor = B
B.left = A
B.right = F
... A < F #left is less than right
D<?F
ancestors(D) = [C]
ancestors(F) = [C,B]
last_common_ancestor = C
C.left = D
C.right = B #next ancestor for F is to the right
... D < F #left is less than right
B<?A
ancestors(B) = [C]
ancestors(A) = [B,C]
last_common_ancestor = B
B.left = A
... A < B #left is always less than parent
Graphquellen