Aufteilung in AVL-Baum mit Komplexität

9

Kann die Aufteilungsoperation für AVL-Bäume mit der Komplexität implementiert werden O(logn)? Ich interessiere mich für Links zu Artikeln oder spezifische Informationen zu diesem Thema.

Die Aufteilungsoperation unterteilt den AVL-Baum basierend auf dem Schlüssel in zwei abgeleitete AVL-Bäume. Einer der abgeleiteten Bäume sollte alle Eckpunkte enthalten, in denen alle Schlüssel kleiner als der ursprüngliche Schlüssel sind, und der zweite den Rest.

Ich weiß, dass dies in O(log2n) Zeit geschehen kann . Hier ist ein Link zur Implementierung mit Komplexität O(log2n) : https://code.google.com/p/self-balancing-avl-tree/

Ich weiß auch, wie man zwei AVL-Bäume in -Zeit zusammenführt, sodass die Schlüssel eines Baums alle kleiner als die Schlüssel des anderen sind O(logn). Hier ist eine Implementierung mit der Komplexität O(logn) :

def Merge(l, r) {
    if (!l || !r) 
        return l ? l : r;
    if (l->h <= r->h)
        r->l = Merge(l, r->l), Rebalance(r);
    else
        l->r = Merge(l->r, r), Rebalance(l);
}
Denis Galeev
quelle

Antworten:

-1

Definieren wir eine Funktion split(T,v), die einen Baum aufnimmt, Tund einen Wert, bei dem geteilt werden soll v. Angenommen, jeder Knoten des Baums speichert zusätzlich zum Wert an diesem Knoten sein linkes und rechtes Kind. Verwenden Sie den folgenden Algorithmus:

  1. Zuerst prüfen wir, ob der Eingabebaum einfach ein Blatt ist oder nicht.

  2. Wenn Tes sich nicht um ein Blatt handelt, vergleichen Sie den Wert seines Wurzelknotens v'mit v.

  3. Wenn v' < vdann rekursiv split im linken Teilbaum aufrufen. Speichern Sie die Werte des rekursiven Aufrufs als L'(zurückgegebener linker Baum), R'(zurückgegebener rechter Baum) und r(Optionstyp gibt an, ob der Wert vgefunden wurde oder nicht). Konstruieren Sie den neuen rechten Baum newR = Node(R',v',R)und kehren Sie zurück (L',r,newR).

  4. Else wenn v' > vdann rekursiv Split auf dem rechten Unterbaum nennen. Speichern Sie die Werte des rekursiven Aufrufs als L'(zurückgegebener linker Baum), R'(zurückgegebener rechter Baum) und r(Optionstyp gibt an, ob der Wert vgefunden wurde oder nicht). Konstruieren Sie den neuen linken Baum newL = Node(L',v',L)und kehren Sie zurück (newL,r,R').

  5. Andernfalls v' = vkehren Sie zurück L, SOME(v), R.

  6. Wenn Tes sich um ein Blatt handelt, müssen wir die Wurzel des Baums erreicht haben, ohne den Eingabewert v zu finden, bei dem geteilt werden soll. Geben Sie zurück, dass Sie das Blatt nicht finden konnten, indem Sie zurückgehen NONE.

Warum ist das logarithmisch? Nun, Sie überqueren höchstens einen Wurzel-Blatt-Pfad des Baumes. Wir können Knoten leicht in konstanter Zeit rekonstruieren, da wir nur -Referenzen (in einer imperativen Sprache) neu zuweisen oder -Werte neu zuweisen , deren Generierung (in einer funktionalen Sprache eine konstante Zeit in Anspruch nimmt) ).O(logn)O(logn)

Hier ist der entsprechende Code für den Algorithmus. Es ist in SML geschrieben, aber ich wäre bereit zu klären, was irgendetwas in den Kommentaren bedeutet.

fun split(T,v) = case T of Leaf => (Leaf, NONE, Leaf) | Node(L,v,R) => case compare(v, v') of LESS => let val (L',r,R') = split(L,k) in (L',r,Node(R',r,R)) end | GREATER => let val (L',r,R') = split(R,k) in (Node(L',v',L),r,R') end | EQUAL => (L, SOME(v), R)

Weitere Informationen finden Sie in diesem Dokument . Es bietet eine gründlichere Erklärung der oben genannten.

Bharadwaj Ramachandran
quelle
Dies berücksichtigt nicht die AVL-Kontostandbedingungen.
jbapple