Seminararbeit über „Near-optimal fully-dynamic graph connectivity“ (M. Thorup) von David Iwanowitsch Worum geht es? Anfragen der Form connected(v,w) an den Graphen sollen beantworten, ob es einen Pfad zwischen den Knoten v und w gibt. Zwischen den Anfragen können im Graph Kanten gelöscht und hinzugefügt werden. Ziel Die bisherige Update-Zeit für Lösch- und Einfügeoperationen Olog n ² soll auf O log nlog log n ³ erwartete amortisierte Zeit verbessert werden. Verbindungsanfragen können dann in O log n/log log log n Zeit beantwortet werden. Die erreichte Komplexität ist nur um einen doppelt logarithmischen Faktor größer, als die allgemeine untere Schranke für Cell-Probe-Probleme log n /log log n . Voraussetzungen: Graph G mit fester Knotenmenge V, ∣V∣=n . G kann verändert werden, durch das Einfügen und Entfernen von Kanten Im Normalfall wird mit einer leeren Kantenmenge gestartet. Zwischen den Änderungen kann es zu Verbindungsanfragen kommen: connected(v,w) liefert ob die beiden Knoten über einen Pfad verbunden sind. Vorgehensweise: Das Problem wird reduziert auf das Problem einen Spannenden Wald über den Graphen zu legen und zu warten.. Wird der Baum in Ot nlog n erzeugt, ist es über diesen möglich, mit Hilfe dynamischer Bäume Verbindungsanfragen in O log n/log t n zu beantworten. Konkret wird t n=log log n ³ erreicht. Startpunkt ist der Algorithmus von Holm, de Lichtenberg und Thorup, zu dem gezeigt wird, wie man die Baumoperationen besser organisieren und verarbeiten kann. Algorithmus nach Holm et al. Über den Graph G wird ein Spannender Wald F gelegt, dessen Kanten wir „Baumkanten“ nennen. Mit jeder Kante e wird ein Level l e ≤l max=log 2 n verbunden. Gi ist der Teilgraph, bestehend aus allen Kanten mit l≥i . Fi analog. Es gelten folgende Invarianten: 1) F ist maximaler (in Bezug zu l), spannender Wald von G, Fi ist spannender Wald von Gi 2) Die maximale Anzahl von Knoten in Gi (Fi) ist abgerundet(n/2i). Daher ergibt sich lmax. David Iwanowitsch 14.05.2008 Seite 1 von 4 Initial haben alle Kanten Level l=0. Die Amortisation geschieht über das Erhöhen der Level. Ein Level wird nur bei der Löschung verkleinert. Algorithmus – Insert(e): l(e):=0, Wenn die Endpunkte in F0 noch nicht verbunden sind wird e zu F0 zugefügt. (1)(2) bleiben erfüllt. – Delete(e): Wenn e keine Baumkante ist, wird sie gelöscht, sonst wird Replace(e) aufgerufen – Replace(e=(v,w)): Nach (1) muss eine Ersetzungskante mindestens Level l(e) haben Seien Tv und Tw die beiden Bäume in die Fl(e) zerfällt. Wir suchen eine Kante, die beide verbindet. Sei Tv der kleinere Baum. Für alle nicht-Baumkanten in Tv: Wenn beide Enden in Tv liegen: Level erhöhen als „Bezahlung“. Wenn nicht, ist die Kante die gesuchte und wird ersetzt. Fertig. Wenn keine Level l(e) Kante gefunden wird: Rekursion mit um eins verkleinertem l(e), bis l=0, dann Ende. Algorithmus anpassen 1) Passende Ersetzungskante finden G, F wie bei Holm Es wird ein gewurzelter Wald C erstellt, dessen Blätter den Knoten in G entsprechen. Level l entspricht der Tiefe eines Knotens. Jeder Knoten a in C erhält eine Größe n a , die der Anzahl von Nachfolgenden Blättern entspricht. v i entspricht dem Vorgänger von v, der l max – i Schritte oberhalb im Baum liegt. Zwei Knoten in C können Zusammengefasst werden, wenn sie entweder Geschwister oder beide Wurzeln sind. Knoten a und b zusammenfassen bedeutet, die Kinder von b an a zu hängen. 1.1) C aktualisieren Werden nicht-Baumkanten gelöscht/eingefügt, ändert C sich nicht. Baumkanten einfügen führt zum Zusammenfassen der Wurzeln beider Teilbäume, die neue Größe des Baumes entsteht dabei durch Addition. Baumkanten löschen: Ersetzungskante mit gleichem Level i suchen, dabei werden die Level der Kanten erhöht, Sei (x,y) ein solche Kante. Das bedeutet für C, das die Knoten x i1 und y i y zusammengefasst werden. Wenn eine Kante gefunden wurde: das Ersetzen betrifft C nicht. Wenn keine Kante gefunden wurde: Bäume werden gesplittet und in höherer Ebene eingefügt. 2) Um Suchen nach (nicht-)Baumkanten durchzuführen wird C erweitert Zwischen jeden Knoten a in C und seine Kinder wird ein balancierter Binärbaum L(a) eingefügt. Der erhaltene Baum heißt CL, hat Tiefe O(log n). In O(log n) lässt sich von einem Blatt zur Wurzel traversieren. Eine Kante (v,w) kann als Baumkante identifiziert werden durch Prüfen von v0=w0 in O log n . Analog kann man Ersetzungskanten auf ihre Eignung testen. Für jeden Knoten a in CL werden zwei Bitmaps erzeugt: tree(a) und nontree(a), die für jeden Level i enthalten, ob es ein nachfolgendes Blatt gibt, das eine angrenzende Baum- bzw. nicht-Baumkante hat. David Iwanowitsch 14.05.2008 Seite 2 von 4 Für jeden Knoten in G haben wir jetzt die Informationen, ob angrenzende Kanten mit bestimmtem Level existieren die Baum- bzw. nicht-Baumkante sind. Da es max. 2log n Bitmaps an den Blättern gibt, kann man diese über einen Suchbaum in O log log n erreichen. Wir können in O log n Zeit zu einem beliebigen Knoten in CL herausfinden, ob es an den Blättern angrenzende Baumkanten gibt oder nicht. 3) Maßgeschneiderte Datenstruktur Jedem Knoten b wird ein rang b=log nb zugeordnet Greedy-Algorithmus für die Kinder eines Knotens b: Start: Jedes Kind ist Wurzel Solange zwei Knoten den gleichen Rang r haben: beide werden unter einer neuen Wurzel zusammengefasst. Die neue Wurzel hat Rang r+1. Die höchstens log n Wurzeln werden über einen Pfad P verknüpft: von b in absteigender RangReihenfolge. 3.1) Anpassung der Methoden Merging: Wir schneiden beide Teilbäumen ab, so dass wir 2log n Wurzeln erhalten, diese werden nach Rang-Größe gemerged und wieder über einen Pfad an den übergeordneten Knoten gehangen. Adding: Wie Merging, nur das der eine Teil nur aus dem neuen Knoten besteht. Removing (a von b): Wir entfernen den Pfad P von b, und erhalten eine Liste von Teilbäumen mit Rängen, suchen daraus den Teilbaum der a enthält, entfernen dort den Pfad von a zur Wurzel und erhalten wieder eine Menge von Teilbäumen mit Rang. Diese beiden Mengen werden gemerged. Bitmaps updaten: Bei Änderungen an der Baumstruktur müssen die Bitmaps aktualisiert werden. Bei den obigen Operation werden je O(log n) Knoten verändert. Die Aktualisierung erfolgt von unten nach oben: Jedes Update ist ein bitweises 'oder' zwischen beiden Kindern. → Jeder Implementierungsteil braucht O(log n) Zeit pro Leveländerung, von denen wir O(log n) pro Kante haben (amortisiert). → Pro Kante brauchen wir Olog n2 Zeit (amortisiert). 4) Von log(n) nach log log n 4.1) Lokale Bäume aufbauen L(a) ist der binäre Baum, mit dem C^L gebaut wurde. Sei B die Menge von Kindern von einem Knoten a aus C. Die Kinder werden in Gruppen mit maximaler Größe 2 log n aufgeteilt (α>2 konstant). Über jede Gruppe kann man per Standardsuchbaum in O log log n Zeit suchen. Analog zum vorherigen Abschnitt werden die Suchbäume nach Rang paarweise zusammengefasst und formen so einen neuen Suchbaum, dessen Operationszeit immer noch O log log n ist. → aus den Abschnitten 3) und 4.1) ergibt sich eine Höhe von O log n log log n für CL. David Iwanowitsch 14.05.2008 Seite 3 von 4 Für jeden so entstandenen Baum gibt es eine Bitmap, die die Ränge der darunter liegenden Bäume enthält. Bei einem Merge können so gemeinsame Ränge schnell gefunden werden. 4.2) Angrenzende Kanten finden Ziel: Schnelles finden einer angrenzenden Kante mit passendem Level, von einem Knoten in CL aus. Jeder Knoten enthält eine Power p≤2log log n . – Innere Knoten der Suchbäume aus (4.1) erhalten p=0. – Sonst, wenn der Rang eines Knotens >0 ist, ist p = Bit mit dem niedrigsten Stellenwert von i. – Wenn Rang = 0 ist: p = log log n. Sei a ein Vorgänger von b: alle Knoten von a bis b haben Power qmin pa , p b , dann ist (a,b) eine Abkürzung mit Power q. Der maximale Pfad von a nach b liegt jetzt in O log log n , da inneren Suchbäumen übersprungen werden können. Da es maximal O(log n) Abkürzungen zu einer angrenzenden Kante gibt, kann man die passende Abkürzung über einen Suchbaum in O log log n Zeit finden. =>Wir können über die Abkürzungen in Olog log n2 Zeit zu einer gewünschten Kante wandern. 4.2.1) Anpassung der Abkürzungen Dazu werden die Abkürzungen von Level i in den i+1-Teilbaum gemerged. Löschen/Einfügen: in CL werden durchgeführt, indem für den einzufügende/zu löschenden Knoten gefordert wird, dass p=0 ist. Dazu wird die Power kleiner gepusht, indem darunter liegende Abkürzungen neu aufgebaut werden. Merging: Die zusammenzufassenden Knoten müssen p=0 haben, daher muss man nur die inneren Abkürzungen beachten. Da Abkürzungen aber nicht über die Rang-Wurzeln hinaus gehen, muss man nur aktualisieren, wenn eine neue Wurzel erstellt wird bzw. eine bestehende gelöscht wird. Da wir dann nur den Pfad entlang gehen müssen um Abkürzungen zu entfernen/erstellen ist das auch in Olog log n2 Zeit möglich. 5) Abschluss Zu guter Letzt müssen die Kanten von G beachtet werden, die nicht im Spannbaum liegen. Dazu müssen die Abkürzungen um ein Gewicht erweitert werden, das die Anzahl der darunter liegenden angrenzenden Baumkanten enthält. Dieses wird entlang der Abkürzungen in Olog log n2 Schritten aktualisiert. Da es O log log n Abkürzungen gibt, die berücksichtigt werden müssen, braucht die Gewichtsaktualisierung Olog log n3 Zeit. Pro Kantenleveländerung werden also Olog log n3 Kosten verursacht. Daraus ergibt sich eine amortisierte Zeit pro Update von O log nlog log n3 . David Iwanowitsch 14.05.2008 Seite 4 von 4