0.0.1 Rot-Schwarz Bäume 0.0.2 Wörterbuchproblem für Wörter bzw

Werbung
0.0.1
Rot-Schwarz Bäume
Rot-Schwarz Bäume sind binäre Suchbäume, deren Knoten entweder “rot” oder
“schwarz” gefärbt sind, d.h. sie werden unterschiedlich gekennzeichnet. Wie bei
anderen Binärbäumen befinden sich die Daten in den Blättern. Dazu haben
Rot-Schwarz Bäume folgende Eigenschaften:
• jedes Blatt ist schwarz,
• rote Knoten haben zwei schwarze Kinder,
• jeder Weg von der Wurzel bis zu einem Blatt hat die gleiche Anzahl schwarzer Knoten.
Daraus folgt, dass Rot-Schwarz Bäume logarithmische Höhe haben. Damit RotSchwarz Bäume beim Einfügen eines Elementes diese Eigenschaften bewahren,
werden dabei wenn erforderlich Rotationen durchgeführt (so wie bei AVL-Bäumen).
Beispiel. Ein Rot-Schwarz Baum kann beispielhaft folgendermaßen aussehen:
Bemerkung. Wenn man rote Knoten mit ihren schwarzen Vätern verschmilzt
(siehe Kreise auf der Abbildung), wird ein Rot-Schwarz Baum zu einem (2,4)Baum.
Dies ist ausserdem auch der Fall bei Bruderbäumen : wenn man Vaterknoten
mit ihren Einzelkindern verschmilzt, bekommt man einen AVL-Baum.
0.0.2
Wörterbuchproblem für Wörter bzw. Strings
Gegeben ist ein endliches Alphabet Σ, wobei |Σ| = k. Das Universum ist die
Menge der Wörter in Σ∗ .
1
Das Problem ist das gleiche wie beim normalen Wörterbuchproblem, bezogen
auf dieses Universum. Man möchte also Elemente suchen, einfügen und streichen
können.
Anwendungen
Dieses Problem ist für folgende Anwendungen relevant:
• Für Suchmaschinen im Internet, da man nach bestimmten Strings in Internetseiten sucht.
• In der Bioinformatik, da bei der Genomanalyse Teilstrings bei der Suche
nach einem “größten gemeinsamen Superstring” manipuliert werden.
• Für Datenkompression, weil es in einer Sprache etwa 60000 Wörter gibt,
mit jeweils im Mittel 5 Zeichen, also insgesamt 300000 Zeichen.
Aber log(300000) ' 18, also 3 Bytes, aber man benutzt im Mittel 5 Bytes.
Es bleiben also 2 Bytes zum Komprimieren übrig.
Datenstruktur
Die benutzte Datenstruktur für das Problem ist der “Trie” (vom englischen retrieval), auch “digitaler Suchbaum” genannt.
Es ist ein Suchbaum, in dem jeder Knoten einen Buchstaben enthält. Jedes
seiner Kinder enthält den nächsten Buchstaben, der in einem der Wörter des
Alphabets vorkommen. So wird ein Wort also durch einen Weg von der Wurzel
zu einem Knoten dargestellt. Man muss also Knoten, die das Ende eines Wortes
darstellen, speziell markieren.
Bemerkenswert ist dabei, dass die Wurzel des Baumes keine Information enthält,
da die Wörter ja nicht alle mit dem gleichen Buchstabe anfangen. Andernfalls
müsste man einen Baum pro Anfangsbuchstabe haben.
Beispiel. Sei das Alphabet Σ = {der, die, das, einer, eine, eines}.
Erstellen wir den dazugehörenden Trie:
Laufzeit der Operationen
Suchen, Einfügen und Streichen eines Wortes W der Länge |W | dauert O(|W |).
|W | ist nämlich die Länge des Weges, der vom ersten Buchstabe bis zum letzten
Buchstabe führt, da in jedem Knoten nur ein Buchstabe gespeichert wird.
Verbesserung
Man kann dies etwas verbessern, indem man Folgen von Knoten, die nur ein
Kind haben, einfach in einem Knoten zusammenschmilzt, wie beim folgenden
Beispiel:
Knotenorganisation
In der Regel besteht jeder Knoten aus einem Feld oder einer verketteten Liste
von Verweisen auf die Kind-Knoten.
Um schnell feststellen zu können, ob ein Knoten ein Kind hat, das einen bestimmten Buchstaben enthält, kann man für jeden Knoten einen Bit-array der
Größe des Alphabets speichern.
2
d
a
s
e
e
u
i
r
e
i
n
e
n
s
Abbildung 1: Beispiel : trie
eine
s
r
Abbildung 2: Verbesserung zum trie
0.1
Das Vereinige-Finde-Problem
(auch “Union-Find” oder “Disjoint Sets”)
Abstrakter Datentyp
Der abstrakte Datentyp, der dieses Problem darstellt, ist eine feste endliche
Menge S (o.B.d.A. ist S = {1,...,n}).
Sei S eine Partition von dieser Menge S, mit S = {S1 , ..., Sk }
Sk
(d.h. i=1 Si = S und ∀i, j mit i 6= j: Si ∩ Sj 6= ∅).
Jedes Si wird durch einen Repräsentanten - einem seiner Elemente - dargestellt.
Operationen
Bezüglich dieser Menge sollen folgende Operationen möglich sein:
• VEREINIGE(Si , Sj ) mit Si , Sj zwei Repräsentanten.
Diese Operation verschmilzt zwei Mengen der Partition S zu einer einzigen. Die Partition wird also sozusagen “vergröbert”.
Formal kann man es folgenderweise darstellen : S := S \ {Si , Sj } ∪ {Si ∪
Sj }).
• FINDE(a) mit a ∈ S.
3
Diese Operation liefert den Repräsentanten von der Menge Si aus S, die
a enthält.
Anwendungen
Dieses Problem hat folgende Anwendungen :
• Sei G = (V, E) ein ungerichteter Graph. Die Zusammenhangskomponente
von G zu finden, ist ein Vereinige-Finde Problem :
Sei S die Menge der Knoten und S zunächst eine Menge von n einelementiger Mengen.
Man durchläuft die Menge E der Kanten ; für jede Kante : e = (u, v).
Falls Si =FINDE(n)6= FINDE(v)=Sj , dann VEREINIGE(Si ,Sj ).
Zum Schluß enthält S die Zusammenhangskomponente von G.
• Bei der Suche nach minimal spannende Bäume (siehe später im Skript).
• Bei der Bildverarbeitung, wenn man “Segmentierung” machen möchte,
also das Einteilen des Bildes in mehrere ähnliche Zonen (der Farbe nach).
• In der Sprache Fortran gibt es den Befehl EQUIVALENCE(x,y), der zwei
Variablen x und y gleichstellt.
Beim Kompilieren gibt es dann ein solches Vereinige-Finde Problem, wenn
mehrere EQUIVALENCE-Befehle im Code vorkommen. (z.B. EQUIVALENCE(x,y)
und EQUIVALENCE(y,z) ).
Datenstruktur
Die verwendete Datenstruktur für das Problem ist ein “Wald”, also eine Menge
von Bäumen.
Für jede Menge Si steht ein Baum, dessen Knoten die Elemente von Si enthalten.
Verweise sind Kind-Vater-Verweise (und nicht Vater-Kind-Verweise wie z.B. bei
Binärbäumen).
Dabei ist der Repräsentant der Menge Si , die Wurzel des Baumes.
9
(1)
3
2
6
8
7
1
4
5
Abbildung 3: Beispiel : Wald
Laufzeit von Vereinige-Finde Operationen
Analysieren wir kurz die Laufzeit dieser Operationen :
• VEREINIGE(Si ,Sj ):
Diese Operation macht die Wurzel eines der beiden Bäume zum Kind der
anderen Wurzel.
Das dauert nur O(1) Zeit, weil es nur eine Zeigermodifikation ist.
4
Beispiel. siehe Pfeil (1) auf Abbildung 3.
• FINDE(a):
Diese Operation erfolgt folgenderweise : Man erhält zunächst einen Verweis auf die Stelle des Waldes, wo sich a befindet. Von dort folgt man den
Vaterverweisen bis zur Wurzel.
Der Verweis auf die Wurzel wird dann geliefert, da diese den Repräsentanten enthält.
Die Laufzeit dieser Operation ist also O(h) wobei h die Höhe des Baumes ist, der a enthält, da wir den ganzen Baum von unten nach oben
durchlaufen.
Im schlechtesten Fall ist das Θ(n), wenn der Wald einen einzigen Baum
enthält, und dieser in Form einer Liste ist (2).
(1)
(2)
Abbildung 4: Alternative (1) wird angestrebt
Dies kann aber verbessert werden, indem bei der VEREINIGE-Operation
der Baum mit geringerer Höhe an die Wurzel des anderen gehängt wird
(Wenn beide Höhen gleich sind ist es egal).
Dazu braucht man ein zusätzliches Feld “Höhe”. Wenn i ein Repräsentant
ist, ist Höhe[i] die Höhe des entsprechenden Baumes.
Behauptung 0.1.1. Höhenbalancierung
Falls die Startsituation so ist, dass jedes Element der Partition nur ein Element
entält ( Si = {i}, i=1,...,n), dann kann eine Folge von VEREINIGE-FINDE
Operationen ausgeführt werden, so dass die Höhe eines entstandenen Baumes
mit k Knoten nie größer ist als dlog(k)e.
Satz 0.1.2. Mit Höhenausgleich gilt also:
• VEREINIGE-Operationen erfolgen in O(1) Zeit (dazu ist die Höheninformation der Wurzel mit einem Feld in konstanter Zeit aktualisierbar)
• FINDE-Operationen erfolgen in O(log(n)) Zeit.
5
Herunterladen