6 Abfragen orthogonaler Bereiche

Werbung
6 ABFRAGEN ORTHOGONALER BEREICHE
6
6.1
Abfragen orthogonaler Bereiche
1-dimensionale Bereichsabfragen
Wir suchen für eine feste Menge P := {p1 , . . . , pn } und variable Intervalle [x, x′ ] alle
Elemente von P ∩ [x, x′ ]. Dafür wählen wir einen balancierten binären Suchbaum T als
Datenstruktur für P . Die Blätter von T enthalten die Punkte von P . Die internen Knoten
v von T speichern Vergleichswerte xv , um die Suche zu leiten: im linken Teilbaum sind
genau die Punkte p mit p ≤ xv .
Algorithmus 6.1
Eingabe: ein Baum T und zwei Zahlen x, x′ mit x ≤ x′
Ausgabe: der Knoten v, an dem sich die Pfade zu x und x′ trennen oder das Blatt, mit
dem beide Pfade enden
1: Funktion FindeTrennKnoten(T , x, x′ )
2:
v ← Wurzel(T )
3:
Solange v kein Blatt von T ist und (x′ ≤ xv oder x > xv ), mache
4:
Wenn x′ ≤ xv dann
5:
v ← linkerSohn(v)
6:
sonst
7:
v ← rechterSohn(v)
Eingabe: ein binärer Suchbaum T und ein Bereich [x, x′ ]
Ausgabe: alle Punkte, die in P gespeichert sind und im Bereich [x, x′ ] liegen
8: Funktion 1DBereichsAbfrage(T , [x, x′ ])
9:
vt ←FindeTrennKnoten(T , x, x′ )
10:
Wenn vt ein Blatt ist, dann
11:
teste, ob der Punkt in vt in [x, x′ ] liegt und liefere diesen gegebenenfalls zurück.
12:
sonst
13:
⊲ Wir folgen dem Pfad zu x und liefern alle Punkte in Teilbäumen rechts des
Pfades.
14:
v ← linkerSohn(vt )
15:
Solange v kein Blatt ist, mache
16:
Wenn x ≤ xv dann
17:
LiefereTeilbaum(rechterSohn(v))
18:
v ← linkerSohn(v)
19:
sonst
20:
v ← rechterSohn(v) .
21:
Liefere gegebenenfalls den Punkt, der in v gespeichert ist.
22:
Folge analog dem Pfad zu x′ und liefere dabei alle Punkte in Teilbäumen links
des Pfades. Behandel das gefundene Blatt.
Lemma 6.2 Die Funktion 1DBereichsAbfrage(T , [x, x′ ]) von Algorithm 6.1 liefert
genau die gesuchten Punkte.
Satz 6.3 Sei P eine Menge von n Punkten im 1-dimensionalen Raum. Dann kann P
in einem balancierten binären Suchbaum in Zeit in O(n log n) gespeichert werden, was
Speicherplatz in O(n) benötigt. Damit können Punkte im Abfragebereich innerhalb einer
Zeit in O(log n + k) gemeldet werden, wobei k die Anzahl der gelieferten Punkte ist.
Algorithmische Geometrie, WS 2009/10
28
TUM, M9, Dr. Nico Düvelmeyer
6 ABFRAGEN ORTHOGONALER BEREICHE
6.2
6.2.1
Kd-Baum
Struktur
Es sei P nun eine Menge von n Punkten der Ebene. Wir nehmen an, dass keine zwei Punkte
die selben x-Koordinaten haben und auch keine zwei Punkte die selben y-Koordinaten
haben. Wir suchen alle Punkte von P im Rechteck R := [x, x′ ] × [y, y ′ ].
Verallgemeinerung des 1D-Prinzips zum Bauen der Suchstruktur: immer den Bereich
in zwei gleich große Teile aufteilen, dort rekursiv Teilbäume bauen und dies zum Gesamtbaum zusammensetzen. Wegen zwei Koordinatenrichtungen wechseln wir einfach von
Schritt zu Schritt zwischen horizontalen und vertikalen Trenngeraden. Diese gehen jeweils
durch einen Punkt von P .
6.2.2
Aufbau
Algorithmus 6.4
Eingabe: eine Punktmenge P ⊂ R2 und eine aktuelle Tiefe t
Ausgabe: die Wurzel eines Kd-Baums, der P speichert
1: Funktion BaueKdBaum(P, t)
2:
Wenn P nur einen Punkt enthält, dann
3:
liefere ein Blatt, das genau diesen Punkt speichert.
4:
sonst
5:
Wenn t gerade ist, dann
6:
teile P durch eine vertikale Gerade l in zwei Teilmengen. Dabei soll l durch
den Punkt von P gehen, dessen x-Koordinate der kleinste Median der x-Koordinaten
von P ist. P1 ist die Menge der Punkte in P , die links von l oder auf l liegen, und
P2 ← P \ P1 .
7:
sonst
8:
Teile P durch eine horizontale Gerade l in zwei Teilmengen. Dabei soll
l durch den Punkt von P gehen, dessen y-Koordinate der kleinste Median der yKoordinaten von P ist. P1 ist die Menge der Punkte in P , die unterhalb von l oder
auf l liegen, und P2 ← P \ P1 .
9:
vl ← BaueKdBaum(P1 , t + 1)
10:
vr ← BaueKdBaum(P2 , t + 1)
11:
Erzeuge einen neuen Knoten v mit linkem Sohn vl und rechten Sohn vr , in dem
l gespeichert ist.
12:
Liefere v zurück.
Lemma 6.5 Ein Kd-Baum für eine Menge von n Punkten der Ebene benötigt Speicherplatz in O(n) und kann in Zeit in O(n log n) konstruiert werden.
Beweis Der Median kann in linearer Zeit gefunden werden, jedoch nur mit einem kompliziertem Algorithmus. Wir umgehen dies durch Vorsortierung der Punkte in zwei Listen
nach x- beziehungsweise nach y-Koordinate. Der Aufbau dieser Listen brauchen einmalig Zeit in O(n log n). Während der weiteren Bearbeitung können die Listen in linearer
Algorithmische Geometrie, WS 2009/10
29
TUM, M9, Dr. Nico Düvelmeyer
6 ABFRAGEN ORTHOGONALER BEREICHE
Zeit aktuell gehalten werden und liefern in konstanter Zeit den Median. Wir erhalten die
folgende Rekursion für die oberer Laufzeitschranke T (n)
(
O(1),
falls n = 1
T (n) =
O(n) + 2T (n/2), falls n > 1 ,
und damit T (n) ∈ O(n log n).
6.2.3
Abfrage mit dem Kd-Baum
Zu jedem Knoten v gehört ein rechteckiger Bereich b(v) der Ebene. Dieser kann teilweise
unbeschränkt sein, ist aber sonst nach rechts und oben abgeschlossen, nach links und
unten dagegen offen. Wir steigen rekursiv in alle Teilbäume ab, deren Bereich den Abfragebereich R schneidet. Liegt b(v) ganz in R, so können wir diesen Teilbaum mittels
LiefereTeilbaum(v) direkt ausgeben.
Algorithmus 6.6
Eingabe: die Wurzel v eines (Teilbaumes von einem) Kd-Baum, und ein Bereich R
Ausgabe: alle Punkte in Blättern des Kd-Baums, die in R ∩ b(v) liegen
1: Funktion SucheImKdBaum(v, R)
2:
Wenn v ein Blatt ist, dann
3:
liefere den Punkt in v, falls er zu R gehört.
4:
sonst
5:
Wenn b(linkerSohn(v)) ⊂ R, dann
6:
LiefereTeilbaum(linkerSohn(v))
7:
sonst
8:
Wenn b(linkerSohn(v)) ∩ R 6= ∅, dann
9:
SucheImKdBaum(linkerSohn(v), R)
10:
Wenn b(rechterSohn(v)) ⊂ R, dann
11:
LiefereTeilbaum(rechterSohn(v))
12:
sonst
13:
Wenn b(rechterSohn(v)) ∩ R 6= ∅, dann
14:
SucheImKdBaum(rechterSohn(v), R)
Während der Rekursion kann b(v) mit bestimmt werden. Algorithmus 6.6 ist unabhängig
von der geometrischen Form von R gültig, R muss dazu kein Rechteck sein.
Lemma 6.7 Eine Abfrage mit einem √
achsenparallelen Rechteck in einem Kd-Baum, der
n Punkte speichert, kann in Zeit in O( n + k) ausgeführt werden, wobei k die Anzahl der
gelieferten Punkte bezeichnet.
Beweis LiefereTeilbaum(·) braucht lineare Zeit in der Anzahl der dabei gelieferten
Punkte. Folglich brauchen alle Ausführungen von Zeile 6 und 11 zusammen Zeit in O(k).
Die restliche Zeit läßt sich linear durch die Anzahl besuchter Knoten v abschätzen, die
nicht an LiefereTeilbaum(·) übergeben wurden. Für diese Knoten ist b(v) ∩ R 6= ∅
aber b(v) 6⊂ R. Damit muß b(v) den Rand von R schneiden. Wir verlängern gedanklich
die Randkanten von R und schätzen die Anzahl der Schnittpunkte von b(v) (für alle
v) mit den 4 Geraden, die R begrenzen, ab. Wir betrachten als Beispiel eine vertikale
Algorithmische Geometrie, WS 2009/10
30
TUM, M9, Dr. Nico Düvelmeyer
6 ABFRAGEN ORTHOGONALER BEREICHE
Gerade l. Es sei T ein Kd-Baum mit Wurzel v. Dann kann l nur einen der beiden Bereiche
b(linkerSohn(v)) oder b(rechterSohn(v)) schneiden, und entsprechend von den vier Enkeln
b(linkerSohn(linkerSohn(v))) etc. nur zwei. Dies ergibt die folgende Rekursion für die
maximale Anzahl Q(n) der von l geschnittenen Bereiche:
(
O(1),
falls n = 1
Q(n) =
2 + 2Q(n/4), falls n > 1 .
√
√
Dies löst sich zu Q(n) ∈ O( n) auf. Damit ist 4Q(n) ∈ O( n) eine Schranke für die
Anzahl der besuchten Knoten v, die nicht an LiefereTeilbaum(·) übergeben wurden.
Satz 6.8 Ein Kd-Baum für eine Menge von n Punkten der Ebene benötigt Speicherplatz
in O(n) und zum initialisieren Zeit in O(n log n). Eine
√ Abfrage mit einem achsenparallelem Rechteck auf dem Kd-Baum benötigt Zeit in O( n+k), wobei k die Anzahl gelieferter
Punkte ist.
Für Kd-Bäume im Rd , d ≥ 2 gilt ein entsprechender Satz mit folgenden Abschätzungen:
Speicherplatz in O(n), Initialisierungszeit in O(n log n), Abfragezeit in O(n1−1/d + k).
6.3
Range-Baum
√
Wir wollen schneller abfragen können als mit der garantierten Zeit O( n + k) des kdBaumes. Der überlagerte Range-Baum erlaubt dies in Zeit in O(log n + k). Dafür steigt
der Speicherplatzbedarf von O(n) auf O(n log n). Zunächst betrachten wir den (einfachen)
Range-Baum mit einer Abfragezeit in O((log n)2 + k).
Wir suchen in einer ersten Phase nur mit Hilfe der x-Koordinate. Für die zweite Phase
nutzen wir dann angepasste lokale Informationen, um auch die verbliebene 1D-Abfrage
für die zugehörige y-Koordinate effizient lösen zu können.
Algorithmus 6.9
Eingabe: eine Punktmenge P der Ebene
Ausgabe: die Wurzel eines 2-dimensionalen Range-Baums für P
1: Funktion Baue2DRangeBaum(P )
2:
Initialisiere die zugeordnete Struktur: baue einen binären Suchbaum Ts auf der
Menge Py der y-Koordinaten. Speichere in den Blättern von Ts vollständig die Originalpunkte.
3:
Wenn P nur einen Punkt enthält, dann
4:
erzeuge ein Blatt v, das genau diesen Punkt und Ts speichert.
5:
sonst
6:
Teile P in zwei Teilmengen auf. Dazu sei xm der kleinste Median aller xKoordinaten in P . P1 sei die Menge der Punkte (x, y) in P mit x ≤ xm , und P2 ←
P \ P1 .
7:
vl ← Baue2DRangeBaum(P1 )
8:
vr ← Baue2DRangeBaum(P2 )
9:
Erzeuge einen neuen Knoten v mit Vergleichswert xv := xm , linkem Sohn vl ,
rechten Sohn vr , und zugeordneter Struktur Ts .
10:
Liefere v zurück.
Algorithmische Geometrie, WS 2009/10
31
TUM, M9, Dr. Nico Düvelmeyer
6 ABFRAGEN ORTHOGONALER BEREICHE
Lemma 6.10 Ein Range-Baum für n Punkte der Ebene benötigt Speicherplatz in
O(n log n).
Beweis Ohne die zugeordneten Strukturen Ts benötigt der primäre Suchbaum linearen
Speicherplatz in n. Jeder Punkt p ∈ P ist in jeder Tiefe des primären Suchbaums in
genau einer zugeordneten Struktur gespeichert. Die maximale Tiefe ist in O(log n). Da
der Speicherplatz jeder zugeordneten Struktur linear von der Anzahl der gespeicherten
Punkte abhängt, ergibt sich die Behauptung.
Algorithmus 6.11
Eingabe: ein 2-dimensionaler Range-Baum T und ein Bereich [x, x′ ] × [y, y ′ ]
Ausgabe: alle Punkte, die in P gespeichert sind und im Bereich [x, x′ ] × [y, y ′ ] liegen
1: Funktion 2DBereichsAbfrage(T , [x, x′ ] × [y, y ′ ])
2:
vt ←FindeTrennKnoten(T , x, x′ )
3:
Wenn vt ein Blatt ist, dann
4:
teste, ob der Punkt in vt in [x, x′ ] × [y, y ′ ] liegt und liefere diesen gegebenenfalls
zurück.
5:
sonst
6:
⊲ Wir folgen dem Pfad zu x und führen 1DBereichsAbfrage(Ts , [y, y ′ ]) für
alle Teilbäume rechts des Pfades aus.
7:
v ← linkerSohn(vt )
8:
Solange v kein Blatt ist, mache
9:
Wenn x ≤ xv dann
10:
1DBereichsAbfrage(Ts (rechterSohn(v)), [y, y ′ ])
11:
v ← linkerSohn(v)
12:
sonst
13:
v ← rechterSohn(v) .
14:
Liefere gegebenenfalls den Punkt, der in v gespeichert ist.
15:
Folge analog dem Pfad von vt zu x′ und führe 1DBereichsAbfrage(Ts , [y, y ′ ]) für alle Teilbäume links des Pfades aus.
Lemma 6.12 Eine Abfrage mit einem achsenparallelem Rechteck in einem Range-Baum
mit n Punkten der Ebene benötigt Zeit in O((log n)2 + k), wobei k die Anzahl der gefundenen Punkte ist.
Beweis Es sei v ein besuchter Knoten von T (ohne Ts ). Ausserhalb von 1DBereichsAbfrage benötigen wir nur konstante Zeit zur Behandlung von v. 1DBereichsAbfrage
benötigt dagegen Zeit in O(log n′ + kv ), wenn Ts genau n′ ≤
Pn Punkte enthält, wovon
kv als Antwort geliefert werden. Die Gesamtzeit
ist damit in v O(log n + kv ), wobei die
P
Anzahl der Summanden in O(log n) und v kv = k ist.
Satz 6.13 Es sei P eine Menge von n Punkten der Ebene. Ein Range-Baum für P kann
mit Speicherplatz in O(n log n) in einer Zeit in O(n log n) aufgebaut werden. Durch eine
Abfrage mit diesem Baum können die Punkte von P innerhalb eines achsenparallelen
rechteckigen Abfragegebietes in Zeit in O((log n)2 +k) bestimmt werden, wobei k die Anzahl
der gelieferten Punkte ist.
Durch fractional cascading“ können wir die Zeit auf O(log n + k) verringern, ohne asym”
ptotisch mehr Speicherplatz zu benutzen.
Algorithmische Geometrie, WS 2009/10
32
TUM, M9, Dr. Nico Düvelmeyer
6 ABFRAGEN ORTHOGONALER BEREICHE
Satz 6.14 Es sei P eine Menge von n Punkten im Rd mit d ≥ 2. Ein Range-Baum
für P kann mit Speicherplatz in O(n(log n)d−1 ) in einer Zeit in O(n(log n)d−1 ) aufgebaut
werden. Durch eine Abfrage mit diesem Baum können die Punkte von P innerhalb eines
achsenparallelen rechteckigen Abfragegebietes in Zeit in O((log n)d + k) bestimmt werden,
wobei k die Anzahl der gelieferten Punkte ist.
Beweis Wir nutzen die selben Ideen wie im 2-dimensionalen Fall mittels Induktion. Der
primäre Suchbaum kann in einer Zeit in O(n log n) aufgebaut werden. Die zugeordneten
Strukturen sind (d − 1)-dimensionale Range-Bäume. Jeder Punkt aus P ist in jeder Tiefe
des primären Baumes in genau einem zugeordneten Baum vertreten. Daher wird für eine
feste Tiefe maximal Speicherplatz und Initialisierungszeit in O(n(log n)d−1 ) benötigt. Die
maximale Tiefe ist in O(log n).
Die Analyse der Abfrage funktioniert analog zu Lemma 6.12.
6.4
Entartete Lage
Bisher hatten wir angenommen, dass keine zwei Punkte aus P eine Koordinate gemeinsam
hatten. Dies wollen wir nun verallgemeinern.
Der Range-Baum mit seinen Operationen kann auch für andere Zahlbereiche neben R
genutzt werden. Diese Zahlbereiche müssen dabei mittels der <-Relation vollständig geordnet sein, unter anderem gilt für zwei Zahlen x und y immer genau eine der drei Beziehungen x < y, y < x oder x = y.
Insbesondere gilt dies auch für Folgen von reellen Zahlen und sogar für Folgen in
R ∪ {+∞, −∞}, wenn wir diese lexikographisch sortieren. Diese Folgen nennen wir zusammengesetzte Zahlen, sie bilden die Menge R̂.
Wir transformieren die Punkte p = (x, y) von R2 nach (R̂)2 mittels p̂ := ((x, y), (y, x)).
Was wird dabei aus einem Rechteck R = [x, x′ ] × [y, y ′ ] in R2 ? Wir wählen folgendes
Rechteck in (R̂)2 :
R̂ := [(x, −∞), (x′ , +∞)] × [(y, −∞), (y ′ , +∞)]
Lemma 6.15 Sei p ein Punkt der Ebene und R ein rechteckiger Bereich. Dann ist p ∈
R
⇐⇒
p̂ ∈ R̂.
Diese Transformation kann durch angepasste Vergleichsfunktionen implementiert werden,
ohne dass die Paare in R̂ explizit gebildet werden müssen. Ersetz man (gedanklich alle
Punkte und Rechtecke, sowie) tatsächlich alle Vergleiche entsprechend dieser Transformation, so erhält man Algorithmen, die nicht mehr die allgemeine Lage ihrer Eingabedaten
voraussetzen. Dabei bleiben alle Abschätzungen gültig.
Dieser Ansatz funktioniert analog in höheren Dimensionen.
Algorithmische Geometrie, WS 2009/10
33
TUM, M9, Dr. Nico Düvelmeyer
6 ABFRAGEN ORTHOGONALER BEREICHE
6.5
Fractional Cascading
Überlagerte Range-Bäume (layered range tree) verbinden die vielen zugeordneten 1dimensionalen Suchstrukturen eines 2-dimensionalen Range-Baumes, damit die wiederholten Abfragen mit selbem Suchbereich in verschiedenen, aber benachbarten Suchbäumen
schneller durchgeführt werden können.
Wir verändern dafür die 1-dimensionale Suchstruktur, die Knoten v zugeordnet ist, zu
einem sortierten Feld. Neben den bisherigen Informationen zu Punkt p (z.B. dessen Koordinaten) enthalten die sortierten Felder auch noch zwei Verweise zu entsprechenden
Positionen des Punktes p in den Listen von linkerSohn(v) und rechterSohn(v). Als entsprechende Position verstehen wir dabei die Position von p oder, falls p nicht in der
anderen Liste enthalten ist, eines Punktes mit nächstgrößerem Such-Schlüssel (dies ist die
letzte Koordinate). Folgt man dem Verweis, so findet man also den kleinsten Punkt der
anderen Liste, der größer oder gleich p ist. Gibt es so einen Punkt nicht, so speichern wir
den symbolischen Wert nil.
Satz 6.16 Sei P eine Menge von n Punkten im Rd , d ≥ 2. Ein überlagerter Range-Baum
für P benötigt Speicherplatz in O(n(log n)d−1 ) und kann in Zeit in O(n(log n)d−1 ) aufgebaut werden. Durch eine Abfrage mit diesem Baum können die Punkte von P innerhalb
eines achsenparallelen rechteckigen Abfragegebietes in Zeit in O((log n)d−1 + k) bestimmt
werden, wobei k die Anzahl der gelieferten Punkte ist.
Beweis Im 2-dimensionalen Fall suchen wird die Anfangsposition des Abfragegebiets
[x, x′ ] × [y, y ′ ], genauer den ersten Punkt (px , py ) mit py ≥ y, in der Suchstruktur Ts (vt )
des Trennknotens vt . Dies braucht Zeit in O(log n). Auf der Suche ausgehend von vt nach
den Werten x und nach x′ halten wir diese Position in jeweils konstanter Zeit aktuell.
Eine Anpassung von LiefereTeilbaum(v) läuft damit in Zeit in O(1 + kv ). Die weitere
Analyse folgt wie zuvor ohne fractional cascading.
Algorithmische Geometrie, WS 2009/10
34
TUM, M9, Dr. Nico Düvelmeyer
Herunterladen