Download as pdf or txt
Download as pdf or txt
You are on page 1of 68

3.

Przeszukiwanie obszarów ortogonalnych


Niech dany będzie zbiór S ⊂ Rd, d ≥ 1. Chcemy wyznaczyć taki podzbiór S ′ ⊆ S
punktów, że każdy z elementów p ∈ S ′ mieści się w zadanym d-wymiarowym
prostopadłościanie R = [x11, x12] × [x21, x22] × · · · × [xd1 , xd2 ], xi1, xi2 ∈ Rd, xi1 ≤ xi2,
i = 1, . . . , d. W geometrii obliczeniowej takie zapytanie nazywa się zapytaniem o
obszar prostokątny (obszar ortogonalny).
zarobki
M. de Berg et al.
Geometria obliczeniowa
J. Kowalski
rozdziały 5 i 10, WNT (2007) 5000 ur. 26.03.1976
zarobki: 3500 USD
Problem. Mając daną bazę danych 3000
pracowników, podać wszystkich pra-
cowników urodzonych między rokiem
1970 a 1976, którzy zarabiają między
3000 a 5000 USD miesięcznie. 19700000 19760000
data urodzenia

Rozwiązanie Jeśli jesteśmy zainteresowani odpowiedzią na zapytanie dotyczące d


pól rekordów, przekształcamy rekordy w punkty d-wymiarowej przestrzeni. Zapy-
tanie o wszystkie rekordy, których pola leżą między poszczególnymi wartościami,
zamienia się wtedy w zapytanie dotyczące wszystkich punktów wewnątrz d-wymia-
rowego prostopadłościanu o bokach równoległych do osi.
3.1 Przeszukiwanie obszarów jednowymiarowych

Problem. Niech S będzie danym zbiorem punktów na prostej rzeczywistej R.


Wejście: Przedział zapytania R = [x1, x2].
Wyjście: Wszystkie punkty z S ∩ R.

49
23 80

10 37 62 89

3 19 30 49 59 70 89 93

3 10 19 23 30 37 59 62 70 80 93 97

Punkty/dane przechowywane są w strukturze zrównoważonego drzewa przeszuki-


wań binarnych T . Liście drzewa T pamiętają punkty S, a węzły wewnętrzne T
przechowują wartości dzielące: lewe poddrzewo węzła v zawiera wszystkie punkty
mniejsze lub równe klucz(v) (wartość pamiętana w węźle v), a prawe poddrzewo
zawiera wszystkie punkty większe od klucz(v).
49
23 80

10 37 62 89

3 19 30 49 59 70 89 93

3 10 19 23 30 37 59 62 70 80 93 97
l1 przedział [18, 77] l2

Idea algorytmu zapytania o przedział [x1, x2]


◮ Poszukujemy liści o kluczach x1 i x2 w drzewie T . Niech l1 i l2 będą liśćmi, w
których kończy się przeszukiwanie.
◮ Wówczas punkty z przedziału [x1, x2] są punktami pamiętanymi w liściach
między l1 i l2 oraz, być może, punktami pamiętanymi w l1 i l2.
Zatem interesują nas liście pewnych poddrzew między ścieżkami przeszukiwań do
l1 i l2. Dokładniej, poddrzewa te są zakorzenione w węzłach, które są między
ścieżkami przeszukiwań i których rodzice są na ścieżce przeszukiwań.

◮ Aby znaleźć te węzły, poszukujemy


najpierw węzła vdziel, w którym
ścieżki do x1 i x2 „rozchodzą się”
(najniższy wspólny przodek dla l1 i l2). T

◮ Zaczynając od vdziel, idziemy dalej


ścieżką poszukiwania x1. W każdym vdziel
węźle, z którego ścieżka skręca w
lewo, wyliczamy wszystkie liście z
jego prawego poddrzewa.
◮ Podobnie podążamy ścieżką po-
szukiwania x2 i wyliczamy liście w
lewym poddrzewie węzłów, w którym
l1 l2
ścieżka skręca w prawo.
◮ Na koniec sprawdzamy punkty pa-
miętane w liściach l1 i l2.
Zatem interesują nas liście pewnych poddrzew między ścieżkami przeszukiwań do
l1 i l2. Dokładniej, poddrzewa te są zakorzenione w węzłach, które są między
ścieżkami przeszukiwań i których rodzice są na ścieżce przeszukiwań.

◮ Aby znaleźć te węzły, poszukujemy


najpierw węzła vdziel, w którym
ścieżki do x1 i x2 „rozchodzą się”
(najniższy wspólny przodek dla l1 i l2). T

◮ Zaczynając od vdziel, idziemy dalej


ścieżką poszukiwania x1. W każdym vdziel
węźle, z którego ścieżka skręca w
lewo, wyliczamy wszystkie liście z
jego prawego poddrzewa.
◮ Podobnie podążamy ścieżką po-
szukiwania x2 i wyliczamy liście w
lewym poddrzewie węzłów, w którym
l1 l2
ścieżka skręca w prawo.
◮ Na koniec sprawdzamy punkty pa-
miętane w liściach l1 i l2.
Zatem interesują nas liście pewnych poddrzew między ścieżkami przeszukiwań do
l1 i l2. Dokładniej, poddrzewa te są zakorzenione w węzłach, które są między
ścieżkami przeszukiwań i których rodzice są na ścieżce przeszukiwań.

◮ Aby znaleźć te węzły, poszukujemy


najpierw węzła vdziel, w którym
ścieżki do x1 i x2 „rozchodzą się”
(najniższy wspólny przodek dla l1 i l2). T

◮ Zaczynając od vdziel, idziemy dalej


ścieżką poszukiwania x1. W każdym vdziel
węźle, z którego ścieżka skręca w
lewo, wyliczamy wszystkie liście z
jego prawego poddrzewa.
◮ Podobnie podążamy ścieżką po-
szukiwania x2 i wyliczamy liście w
lewym poddrzewie węzłów, w którym
l1 l2
ścieżka skręca w prawo.
◮ Na koniec sprawdzamy punkty pa-
miętane w liściach l1 i l2.
Lemat 3.1. Powyższy algorytm wylicza dokładnie te i tylko te punkty z S, które
leżą w obszarze zapytania [x1, x2].
T
Należy wykazać, że każdy ze zgłaszanych

punktów leży w obszarze [x1, x2]. vdziel

Należy wykazać, że każdy punkt ∈ S,



który należy do obszaru [x1, x2],
zostanie zgłoszony.

l1 l2
Lemat 3.1. Powyższy algorytm wylicza dokładnie te i tylko te punkty z S, które
leżą w obszarze zapytania [x1, x2].
T
Należy wykazać, że każdy ze zgłaszanych

punktów leży w obszarze [x1, x2]. vdziel

Należy wykazać, że każdy punkt ∈ S,



który należy do obszaru [x1, x2],
zostanie zgłoszony.

l1 l2
Twierdzenie 3.2. (???)
Niech S będzie zbiorem n punktów na prostej rzeczywistej R. Zbiór S można zapa-
miętać w zrównoważonym drzewie poszukiwań binarnych, które korzysta z pamięci
rzędu O(n) i ma czas konstrukcji O(n log n), tak że punkty w obszarze zapytania
można podać w czasie O(k + log n), gdzie k jest liczbą podawanych punktów.
Liczba węzłów wewnętrznych każdego drzewa binarnego jest mniejsza od liczby

liści, a zatem wyliczenie wszystkich liści danego poddrzewa wymaga czasu
liniowego względem liczby k podawanych punktów.
Jako że drzewo jest zrównoważone, liczba odwiedzanych węzłów przy poszuki-

waniu x1 i x2 wynosi O(log n).
3.2 Zapytania w przestrzeni dwywymiarowej: kd-drzewa

Problem. (Przeszukiwanie obszarów ortogonalnych)


Niech S będzie danym zbiorem punktów na płaszczyźnie rzeczywistej R2.
Wejście: Obszar zapytania R = [x1, x2] × [y1, y2].
Wyjście: Wszystkie punkty z S, które należą do R.

a) b)
l5 l1 l7
l1
p9
p10 l2 l3
p4
p5
l2 l4 l5 l6 l7
p2 l3
p7 p8
l8 l8 p3 p4 p5 l9 p8 p9 p10
p1 p6
l9
p3 p1 p2 p6 p7
l4 l6
(a) Podział płaszczyzny i (b) odpowiadające mu kd-drzewo.
l1
p9
p10 l2 l3
p4
p5
l4 l5 l6 l7
p2
p7 p8
l8 p3 p4 p5 l9 p8 p9 p10
p1 p6
p3 p1 p2 p6 p7

Idea konstrukcji kd-drzewa dla zbioru S ⊂ R2


◮ Dodatkowy parametr d na wejściu (początkowo d = 0).
◮ Jeśli S zawiera tylko jeden punkt, zwróć liść pamiętający ten punkt.
◮ W przeciwnym wypadku, jeśli d jest parzyste, podziel S na dwa zbiory S1 i
S2 pionową prostą l przechodzącą przez medianę współrzędnych x punktów z
S, gdzie S1 zawiera punkty na lewo lub na prostej l, a S2 zawiera punkty na
prawo od prostej l.
◮ ...
l1 d=0
l1
p9
p10 l2 l3
p4
p5
l4 l5 l6 l7
p2
p7 p8
l8 p3 p4 p5 l9 p8 p9 p10
p1 p6
p3 p1 p2 p6 p7

Idea konstrukcji kd-drzewa dla zbioru S ⊂ R2


◮ Dodatkowy parametr d na wejściu (początkowo d = 0).
◮ Jeśli S zawiera tylko jeden punkt, zwróć liść pamiętający ten punkt.
◮ W przeciwnym wypadku, jeśli d jest parzyste, podziel S na dwa zbiory S1 i
S2 pionową prostą l przechodzącą przez medianę współrzędnych x punktów z
S, gdzie S1 zawiera punkty na lewo lub na prostej l, a S2 zawiera punkty na
prawo od prostej l.
◮ ...
l1 d=0
l1
p9
d=1 d=1
p10 l2 l3
p4
p5
l2 l4 l5 l6 l7
p2 l3
p7 p8
l8 p3 p4 p5 l9 p8 p9 p10
p1 p6
p3 p1 p2 p6 p7

Idea konstrukcji kd-drzewa dla zbioru S ⊂ R2


◮ ...
◮ W przeciwnym wypadku, jeśli d jest nieparzyste, podziel S na dwa zbiory S1
i S2 poziomą prostą l przechodzącą przez medianę współrzędnych y punktów
z S, gdzie S1 zawiera punkty poniżej lub na prostej l, a S2 zawiera punkty
powyżej prostej l.
◮ Rekurencyjnie wyznacz kd-drzewa T1 dla S1 oraz T2 dla S2 z parametrem d+1.
◮ Zwróć korzeń v (z prostą l), z T1 jako jego lewym synem, a T2 – prawym.
l5 l1 l7 d=0
l1
p9
d=1 d=1
p10 l2 l3
p4
p5
d=2 d=2
l2 l4 l5 l6 l7
p2 l3
p7 p8
l8 p3 p4 p5 l9 p8 p9 p10
p1 p6
p3 p1 p2 p6 p7
l4 l6

Idea konstrukcji kd-drzewa dla zbioru S ⊂ R2


◮ ...
◮ W przeciwnym wypadku, jeśli d jest nieparzyste, podziel S na dwa zbiory S1
i S2 poziomą prostą l przechodzącą przez medianę współrzędnych y punktów
z S, gdzie S1 zawiera punkty poniżej lub na prostej l, a S2 zawiera punkty
powyżej prostej l.
◮ Rekurencyjnie wyznacz kd-drzewa T1 dla S1 oraz T2 dla S2 z parametrem d+1.
◮ Zwróć korzeń v (z prostą l), z T1 jako jego lewym synem, a T2 – prawym.
l5 l1 l7 d=0
l1
p9
d=1 d=1
p10 l2 l3
p4
p5
d=2 d=2
l2 l4 l5 l6 l7
p2 l3
p7 p8
l8 l8 p3 p4 p5 l9 p8 p9 p10
p1 p6
l9
p3 p1 p2 p6 p7
l4 l6

Idea konstrukcji kd-drzewa dla zbioru S ⊂ R2


◮ ...
◮ W przeciwnym wypadku, jeśli d jest nieparzyste, podziel S na dwa zbiory S1
i S2 poziomą prostą l przechodzącą przez medianę współrzędnych y punktów
z S, gdzie S1 zawiera punkty poniżej lub na prostej l, a S2 zawiera punkty
powyżej prostej l.
◮ Rekurencyjnie wyznacz kd-drzewa T1 dla S1 oraz T2 dla S2 z parametrem d+1.
◮ Zwróć korzeń v (z prostą l), z T1 jako jego lewym synem, a T2 – prawym.
Złożoność czasowa konstrukcji

◮ Podział zbioru S nas S1 i S2, w szczególności wyznaczenie mediany: O(n).


Rozwiązanie prostsze: wystarczy wstępnie posortować zbiór S po współ-

rzędnej x i po y. Wówczas zbiór wejściowy S jest przekazywany do pro-
cedury w postaci dwóch posortowanych list, jednej po współrzędnej x, a
drugiej po współrzędnej y.
◮ Rekurencyjne wyznaczenie kd-drzew dla zbiorów S1 i S2: 2 · T (n/2).
Otrzymujemy
jeśli n = 1,

O(1)
T (n) =
2 · T (n/2) + O(n) w przeciwnym wypadku,
którego rozwiązaniem jest T (n) = O(n log n).

Lemat 3.3. Dla zbioru n-punktów na płaszczyźnie można w czasie O(n log n) skon-
struować dwuwymiarowe kd-drzewo, które korzysta z pamięci rzędu O(n).
Pamięć O(n) − bo drzewo binarne, w którym każdy liść pamięta inny punkt.

Idea algorytmu zapytań

Niech obszar(v) oznacza obszar odpowiadający poddrzewu o korzeniu v.

l1
l1
l2
l3

l2 v

obszar(v)
l3

Odpowiedniość między poddrzewami a obszarami na płaszczyźnie.

◮ Dla danego obszaru zapytania R musimy przeszukać drzewo zakorzenione w v


wtedy i tylko wtedy, gdy R przecina obszar(v), tj. R ∩ obszar(v) 6= ∅.
◮ A zatem przechodzimy kd-drzewo odwiedzając tylko te węzły v, których ob-
szar obszar(v) przecinany jest przez obszar zapytania R, a ponadto:
gdy obszar obszar(v) jest całkowicie zawarty w prostokącie zapytania, mu-

simy podać wszystkie punkty pamiętane w tym poddrzewie;
gdy dotrzemy do liścia (w inny niż w/w sposób), musimy sprawdzić, czy

punkt pamiętany w tym liściu należy do obszaru R i, jeśli tak, zgłosić go.
l1 l6
l1

p12 l2 l3
p4
p2 p5 p13
l2 l4 l4 l5 l6
p8
l3 l4 p3 p4 p5 l7 p11 p12 p13
p10
p1 p7
p9 p11 p1 p2 p6 ∗
l7 p6 p6
p6
p3 R
p7 p8 p9 p10
l4 l5
Wszystkie zielone węzły są odwiedzane, natomiast zgłaszane są jedynie liście p6, p11 oraz te ciemnozielone.
/Uwaga − Przykładowe drzewo nie jest zrównoważonym kd-drzewem./
◮ A zatem przechodzimy kd-drzewo odwiedzając tylko te węzły v, których ob-
szar obszar(v) przecinany jest przez obszar zapytania R, a ponadto:
gdy obszar obszar(v) jest całkowicie zawarty w prostokącie zapytania, mu-

simy podać wszystkie punkty pamiętane w tym poddrzewie;
gdy dotrzemy do liścia (w inny niż w/w sposób), musimy sprawdzić, czy

punkt pamiętany w tym liściu należy do obszaru R i, jeśli tak, zgłosić go.

◮ Zapytanie o przecięcie obszaru R i obszaru odpowiadający pewnemu węzłowi.


Możemy w fazie przetwarzania wstęp-

nego obliczyć dla każdego węzła v l(v)

jego obszar(v) i zapamiętać go. lewa(l(v))

Można też w trakcie wywołania reku-



obszar(lewy-syn(v))
rencyjnego utrzymywać aktualny ob-
szar używając prostych pamiętanych obszar(v)
w węzłach wewnętrznych.
Na przykład:
obszar(lewy-syn(v)) = obszar(v) ∩ lewa(l(v)),
gdzie głębokość węzła v jest parzysta, l(v) jest prostą dzielącą pamiętaną w v,
lewa(l(v)) jest półpłaszczyzną na lewo od l(v), włącznie z l(v).
Lemat 3.4. Zapytanie o prostokąt o bokach równoległych do osi można wykonać
2
w kd-drzewie
√ przechowujących n punktów należących do płaszczyzny R w czasie
O( n + k), gdzie k jest liczbą podawanych punktów.

Przypadek 1: obszar(v) ⊆ prostokąt zapytania R.




Czas przejścia poddrzewa i podania punktów pamiętanych w jego liściach jest


liniowy względem liczby punktów, co wynika z tego, że kd-drzewo jest drzewem
binarnym. Zatem całkowity czas potrzebny do przejścia tych poddrzew wynosi
O(k), gdzie k jest całkowitą liczbą podawanych punktów.
l1 l6
l1

p12 l2 l3
p4
p2 p5 p13
l2 l4 l4 l5 l6
p8
l3 l4 p3 p4 p5 l7 p11 p12 p13
p10
p1 p7
p9 p11 p1 p2 p6 ∗
l7 p6 p6
p6
p3 R
p7 p8 p9 p10
l4 l5
Szacujemy liczbę ciemnozielonych węzłów.
Przypadek 2: obszar(v) 6⊆ prostokąt zapytania R.


Należy oszacować liczbę węzłów X(n), które odwiedzone są przez algorytm


zapytań, a które nie są w tych w/w przechodzonych poddrzewach.

l1 l6
l1

p12 l2 l3
p4
p2 p5 p13
l2 l4 l4 l5 l6
p8
l3 l4 p3 p4 p5 l7 p11 p12 p13
p10
p1 p7
p9 p11 p1 p2 p6 ∗
l7 p6 p6
p6
p3 R
p7 p8 p9 p10
l4 l5
Szacujemy liczbę jasnozielonych lub niebieskich węzłów.
Przypadek 2: obszar(v) 6⊆ prostokąt zapytania R.


Należy oszacować liczbę węzłów X(n), które odwiedzone są przez algorytm


zapytań, a które nie są w tych w/w przechodzonych poddrzewach.

l1 l6
l1

p12 l2 l3
p4
p2 p5 p13
l2 l4 l4 l5 l6
p8
l3 l4 p3 p4 p5 l7 p11 p12 p13
p10
p1 p7
p9 p11 p1 p2 p6 ∗
l7 p6 p6
p6
p3 R
p7 p8 p9 p10
l4 l5

l Szacujemy liczbę jasnozielonych lub niebieskich węzłów.

Aby oszacować X(n), rozważamy liczbę obszarów Q(n) przecinanych przez


dowolną prostą pionową l. W ten sposób otrzymamy górne ograniczenie na
liczbę obszarów przecinanych przez lewą i prawą krawędź obszaru zapytania R.
l
prosta l przecina obszar(korzeń)
l1 l6 Q(n)
l1 prosta l przecina
obszar(lewy-syn(korzeń))
p12 l2 l3
p4
Q(⌈ n4 ⌉)
p2 p5 p13
l2 l4 l4 l5 l6 Q(⌈ n4 ⌉)
p8
l3 l4 p3 p4 p5 l7 p11 p12 p13

p1 p7 p10
p9 p11 p1 p2 p6 ∗
l7 p6 p6
p6
p3 R
p7 p8 p9 p10
l4 l5

Niech l będzie dowolną pionową prostą i niech Q(n) będzie liczbą przecinanych ob-
szarów przez l w kd-drzewie przechowującym n-punktów na płaszczyźnie, którego
korzeń zawiera pionową prostą dzielącą.
jeśli n = 1;

O(1)
Q(n) =
2 + 2 · Q(⌈n/4⌉) w przeciwnym wypadku.

Rozwiązaniem tego równania jest Q(n) = O( n).
l
prosta l przecina obszar(korzeń)
l1 l6 Q(n)
l1 prosta l przecina
obszar(prawy-syn(korzeń))
p12 l2 l3
p4
Q(⌈ n4 ⌉)
p2 p5 p13
l2 l4 l4 l5 l6 Q(⌈ n4 ⌉)
p8
l3 l4 p3 p4 p5 l7 p11 p12 p13

p1 p7 p10
p9 p11 p1 p2 p6 ∗
l7 p6 p6
p6
p3 R
p7 p8 p9 p10
l4 l5

Niech l będzie dowolną pionową prostą i niech Q(n) będzie liczbą przecinanych ob-
szarów przez l w kd-drzewie przechowującym n-punktów na płaszczyźnie, którego
korzeń zawiera pionową prostą dzielącą.
jeśli n = 1;

O(1)
Q(n) =
2 + 2 · Q(⌈n/4⌉) w przeciwnym wypadku.

Rozwiązaniem tego równania jest Q(n) = O( n).
⊲ W analogiczny sposób można udowodnić, że liczba √ obszarów przecinanych
przez dowolną prostą poziomą jest także rzędu O( n).
A zatem całkowita liczba
√ obszarów przecinanych przez brzeg prostokąta zapytania
jest również rzędu O( n).
Twierdzenie 3.5. (Bentley 1975) Kd-drzewo dla n-elementowego zbioru S ⊂ R2
punktów wymaga O(n) pamięci i można je zbudować w czasie O(n log √n). Zapytanie
o prostokątny obszar zapytania dla kd-drzewa wymaga czasu rzędu O( n+k), gdzie
k jest liczbą zgłaszanych punktów.
Twierdzenie 3.5. (Bentley 1975) Kd-drzewo dla n-elementowego zbioru S ⊂ R2
punktów wymaga O(n) pamięci i można je zbudować w czasie O(n log √n). Zapytanie
o prostokątny obszar zapytania dla kd-drzewa wymaga czasu rzędu O( n+k), gdzie
k jest liczbą zgłaszanych punktów.

Wielowymiarowe kd-drzewa
◮ W korzeniu zbiór punktów dzielony jest względem pierwszej współrzędnej tych
punktów. W dzieciach korzenia podział ten dokonywany jest względem drugiej
współrzędnej. W węzłach o głębokości dwa − względem trzeciej współrzędnej.
◮ . . . aż do głębokości d − 1, na której dzielimy względem ostatniej współrzędnej.
◮ Na głębokości d − podział znowu względem pierwszej współrzędnej, itd.
◮ Rekursja zatrzymuje się, gdy pozostał tylko jeden punkt, który zapamiętywany
jest w liściu.
◮ Ponieważ d-wymiarowe kd-drzewo dla zbioru n-punktów jest drzewem binar-
nym o n liściach, więc korzysta ono z pamięci rzędu O(n).
◮ Czas konstrukcji wynosi O(n log n). (Zakładamy, że d jest stałą.)
◮ Można pokazać, że czas zapytania jest rzędu O(n1−1/d + k).
3.3 Dwuwymiarowe drzewa obszarów

Problem. (Przeszukiwanie obszarów ortogonalnych)


Niech S będzie danym zbiorem punktów na płaszczyźnie rzeczywistej R2.
Wejście: Obszar zapytania R = [x1, x2] × [y1, y2].
Wyjście: Wszystkie punkty z S, które należą do R.

Rozważmy zrównoważone drzewo T wyszukiwań binarnych przechowujące w li-


ściach wszystkie punkty z S, o porządku wyznaczonym przez odcięte punktów.

drzewo wyszukiwań
T
binarnych względem
współrzędnej x

S(v) S(v)

Podzbiór S(v) punktów pamiętany w liściach poddrzewa zakorzenionego w danym


wierzcołku v drzewa T nazywany jest podzbiór kanonicznym wierzchołka v.
T
drzewo wyszukiwań
binarnych względem
współrzędnej x
vdziel
O(log n) węzłów
O(log n) węzłów

l1 O(log n) podzbiorów kanonicznych l2

◮ Podzbiór punktów, których współrzędna x leży w jednowymiarowym obszarze


zapytania [x1, x2] można wyrazić jako sumę O(log n) rozłącznych podzbiorów
kanonicznych (pasków) w drzewie T . Są to zbiory S(v) wezłów v, które są
korzeniami odpowiednich poddrzew na ścieżkach poszukiwań x1 oraz x2.
x1 ≤ O(log n) pasków ≤ x2

◮ Podzbiór punktów, których współrzędna x leży w jednowymiarowym obszarze


zapytania [x1, x2] można wyrazić jako sumę O(log n) rozłącznych podzbiorów
kanonicznych (pasków) w drzewie T . Są to zbiory S(v) wezłów v, które są
korzeniami odpowiednich poddrzew na ścieżkach poszukiwań x1 oraz x2.
y2

y1

x1 ≤ O(log n) pasków ≤ x2

◮ Jeśli dla dowolnego S(vi) dostępne jest drzewo wyszukiwań binarnych wzglę-
dem współrzędnej y, wówczas, wykonując jednowymiarowe zapytanie na tym
drzewie, jesteśmy w stanie znaleźć w czasie O(log |S(vi)| + kvi ) wszystkie kvi
punktów z S(vi), których współrzędna y mieści się w przedziale [y1, y2].
Dwupoziomowa struktura danych zwana drzewem obszarów.
◮ Główne drzewo jest zrównoważonym drzewem przeszukiwan binarnych T zbu-
dowanym względem współrzędnej x punktów z S.
Dla każdego węzła wewnętrznego lub liścia v w drzewie T , podzbiór kano-
niczny S(v) jest pamiętany w zrównoważonym drzewie przeszukiwań binarnych
Tstow(v) względem współrzędnej y punktów (tzw. struktura stowarzyszona z v);
węzeł v pamięta wskaźnik do drzewa Tstow(v).

drzewo wyszukiwań
T
binarnych względem
współrzędnej x

S(v)

Na dowolne poddrzewo (zbiór kanoniczny) drzewa Tstow(v) można patrzeć jak


poziomy wycinek pionowego paska S(v).
Dwupoziomowa struktura danych zwana drzewem obszarów.
◮ Główne drzewo jest zrównoważonym drzewem przeszukiwan binarnych T zbu-
dowanym względem współrzędnej x punktów z S.
◮ Dla każdego węzła wewnętrznego lub liścia v w drzewie T , podzbiór kano-
niczny S(v) jest pamiętany w zrównoważonym drzewie przeszukiwań binarnych
Tstow(v) względem współrzędnej y punktów (tzw. struktura stowarzyszona z v);
węzeł v pamięta wskaźnik do drzewa Tstow(v).

drzewo wyszukiwań Tstow (v)


T
binarnych względem
współrzędnej x

drzewo wyszukiwań
binarnych dla S(v)
S(v) względem współrzędnej y

Na dowolne poddrzewo (zbiór kanoniczny) drzewa Tstow(v) można patrzeć jak


poziomy wycinek pionowego paska S(v).
Dwupoziomowa struktura danych zwana drzewem obszarów.
◮ Główne drzewo jest zrównoważonym drzewem przeszukiwan binarnych T zbu-
dowanym względem współrzędnej x punktów z S.
◮ Dla każdego węzła wewnętrznego lub liścia v w drzewie T , podzbiór kano-
niczny S(v) jest pamiętany w zrównoważonym drzewie przeszukiwań binarnych
Tstow(v) względem współrzędnej y punktów (tzw. struktura stowarzyszona z v);
węzeł v pamięta wskaźnik do drzewa Tstow(v).

drzewo wyszukiwań Tstow (v)


T
binarnych względem
współrzędnej x

drzewo wyszukiwań
binarnych dla S(v)
S(v) względem współrzędnej y

◮ Na dowolne poddrzewo (zbiór kanoniczny) drzewa Tstow(v) można patrzeć jak


poziomy wycinek pionowego paska S(v).
Idea algorytmu zapytań
◮ Algorytm wybiera O(log n) struktur stowarzyszonych łącznie zawierających
wszystkie punkty, których wspórzędna x leży w obszarze [x1, x2].
a /Jednowymiarowy algorytm zapytań na drzewie T ./

◮ Z tych podzbiorów zgłaszane są tylko te punkty, których współrzędna y leży


w obszarze [y1, y2]. a /Jednowymiarowy algorytm zapytań na drzewach Tstow ./

O(log n) struktur stowarzyszonych


T
Złożoność czasowa algorytmu

O(log n) struktur stowarzyszonych

W każdym odwiedzanym węźle v drzewa T sprawdzamy, dokąd należy dalej iść,


oraz być może wywołujemy (jednowymiarowy) algorytm zapytań na drzewie Tstow(v)
o czasię rzędu O(log n + kv ), gdzie kv jest liczbą zgłaszanych punktów w wywoła-
niu dla węzła v.P Tym samym całkowity czas zużyty we wszystkich odwiedzonych
węzłach wynosi v O(log n + kv ).
v kv = k, gdzie k jest liczbą wszystkich podanych punktów.
 P

Ścieżki poszukiwań x1 i x2 w drzewie T mają długość rzędu O(log n).



Otrzymujemy zatem v O(log n) = O(log2 n).
P

Wniosek 3.6. W dwuwymiarowym drzewie obszarów przechowującym n-punktów


płaszczyzny R2 zapytanie o prostokąt [x1, x2] × [y1, y2] (o bokach równoległych do
osi) wymaga czasu O(log2 n + k), gdzie k jest liczbą zgłaszanych punktów.
Idea algorytmu budowy dwuwymiarowego drzewa obszarów

Wstępne przetwarzanie: zbiór wejściowy S reprezentowany jest przez parę (Sx, Sy ).


Sx − posortowany zbiór S punktów wejściowych względem współrzędnej x.
Sy − posortowany zbiór S punktów wejściowych względem współrzędnej y.

◮ Zbuduj drzewo wyszukiwań binarnych Tstow dla zbioru Sy rzędnych punktów


z S. W liściach Tstow pamiętaj nie tylko współrzędne y punktów z Sy , ale i
odpowiadające im punkty.
◮ Jeśli wejściowy zbiór S zawiera tylko jeden punkt, to stwórz liść pamiętający
ten punkt i zwiąż z nim Tstow.
◮ W przeciwnym wypadku podziel zbiór S na dwa (prawie) równoliczne pod-
zbiory S1 i S2, gdzie podzbiór S1 zawiera punkty o odciętych mniejszych lub
równych xśrod, medianie współrzędnych x, a podzbiór S2 zawiera punkty o od-
ciętych większych od xśrod.
◮ Wywołaj rekurencyjnie budowę drzewa dla zbiorów S1 oraz S2, otrzynując od-
powiednio poddrzewa T1 i T2, o korzeniach v1 i v2.
◮ Zwróć węzeł/korzeń v pamiętający xśrod, o lewym synu v1, prawym − v2,
związawszy uprzednio Tstow z v.
Idea algorytmu budowy dwuwymiarowego drzewa obszarów

Wstępne przetwarzanie: zbiór wejściowy S reprezentowany jest przez parę (Sx, Sy ).


Sx − posortowany zbiór S punktów wejściowych względem współrzędnej x.
Sy − posortowany zbiór S punktów wejściowych względem współrzędnej y.

◮ Zbuduj drzewo wyszukiwań binarnych Tstow dla zbioru Sy rzędnych punktów


z S. W liściach Tstow pamiętaj nie tylko współrzędne y punktów z Sy , ale i
odpowiadające im punkty.
Zbiór Sy jest posortowany, a zatem „łącząc w pary”, od dołu, można skon-

struować drzewo Tstow w czasie liniowym od rozmiaru S.
◮ ...
Idea algorytmu budowy dwuwymiarowego drzewa obszarów

Wstępne przetwarzanie: zbiór wejściowy S reprezentowany jest przez parę (Sx, Sy ).


Sx − posortowany zbiór S punktów wejściowych względem współrzędnej x.
Sy − posortowany zbiór S punktów wejściowych względem współrzędnej y.

◮ Zbuduj drzewo wyszukiwań binarnych Tstow dla zbioru Sy rzędnych punktów


z S. W liściach Tstow pamiętaj nie tylko współrzędne y punktów z Sy , ale i
odpowiadające im punkty.
Zbiór Sy jest posortowany, a zatem „łącząc w pary”, od dołu, można skon-

struować drzewo Tstow w czasie liniowym od rozmiaru S.
◮ ...

Otrzymujemy następujące równanie rekurencyjne

jeśli n = 1;

O(1)
T (n) =
2 · T (n/2) + O(n) w przeciwnym wypadku,

którego rozwiązaniem jest T (n) = O(n log n). A zatem czas konstrukcji drzewa,
mając na uwadze wykonane wcześniej przetwarzanie wstępne, wynosi O(n log n).
Złożoność pamięciowa algorytmu

Lemat 3.7. Drzewo obszarów dla zbioru n punktów na płaszczyźnie wymaga pa-
mięci rzędu O(n log n).

◮ Drzewo T potrzebuje pamięci rzędu O(n), gdyż mamy n punktów.


Struktury stowarzyszone:
dla wszystkich węzłów na tej samej

głębokości drzewa T punkt p pamię- T
tany jest dokładnie w jednej strukturze
stowarzyszonej;
struktury stowarzyszone na danej głę-

bokości drzewa T pokrywają wszystkie
punkty, stąd wykorzystują one łącznie
O(n) pamięci (na danej głębokości);
głębokość drzewa T wynosi O(log n), a

zatem całkowity rozmiar pamięci wyma-
ganej dla struktur stowarzyszonych ogra-
niczony jest przez O(n log n). 2
Złożoność pamięciowa algorytmu

Lemat 3.7. Drzewo obszarów dla zbioru n punktów na płaszczyźnie wymaga pa-
mięci rzędu O(n log n).

◮ Drzewo T potrzebuje pamięci rzędu O(n), gdyż mamy n punktów.


◮ Struktury stowarzyszone:
dla wszystkich węzłów na tej samej

głębokości drzewa T punkt p pamię- T
tany jest dokładnie w jednej strukturze
stowarzyszonej;
struktury stowarzyszone na danej głę-

bokości drzewa T pokrywają wszystkie
punkty, stąd wykorzystują one łącznie
O(n) pamięci (na danej głębokości);
głębokość drzewa T wynosi O(log n), a

zatem całkowity rozmiar pamięci wyma- p
ganej dla struktur stowarzyszonych ogra-
niczony jest przez O(n log n). 2
Złożoność pamięciowa algorytmu

Lemat 3.7. Drzewo obszarów dla zbioru n punktów na płaszczyźnie wymaga pa-
mięci rzędu O(n log n).

◮ Drzewo T potrzebuje pamięci rzędu O(n), gdyż mamy n punktów.


◮ Struktury stowarzyszone:
dla wszystkich węzłów na tej samej

głębokości drzewa T punkt p pamię-
tany jest dokładnie w jednej strukturze
stowarzyszonej;
struktury stowarzyszone na danej głę-

p
bokości drzewa T pokrywają wszystkie
punkty, stąd wykorzystują one łącznie
O(n) pamięci (na danej głębokości);
głębokość drzewa T wynosi O(log n), a

p
zatem całkowity rozmiar pamięci wyma- p
ganej dla struktur stowarzyszonych ogra-
niczony jest przez O(n log n). 2 p
Złożoność pamięciowa algorytmu

Lemat 3.7. Drzewo obszarów dla zbioru n punktów na płaszczyźnie wymaga pa-
mięci rzędu O(n log n).

◮ Drzewo T potrzebuje pamięci rzędu O(n), gdyż mamy n punktów.


◮ Struktury stowarzyszone: O(n log n).

Otrzymujemy w konsekwencji:
Twierdzenie 3.8. (m.in. Bentley 1979; Lueker 1978)
Niech S będzie zbiorem n punktów na płaszczyźnie R2. Drzewo obszarów dla S
używa O(n log n) pamięci i można je zbudować w czasie O(n log n). Punkty S
leżące w prostokątnym obszarze zapytania można wyznaczyć w czasie O(log2 n+k),
gdzie k jest liczbą zgłaszanych punktów.
3.4 Wielowymiarowe drzewa obszarów

◮ Tworzymy zrównoważone drzewo wyszukiwań binarnych względem pierwszej


współrzędnej danych punktów.
◮ W drzewie tym kanoniczny podzbiór S(v) węzła v składa się z punktów pa-
miętanych w liściach drzewa zakorzenionego w v.
◮ Dla każdego węzła v tworzymy strukturę stowarzyszoną Tstow będącą (d − 1)-
wymiarowym drzewem obszarów dla punktów z S(v), ograniczonych do ich
d − 1 współrzędnych.
◮ Tstow budowane jest rekurencyjnie; rekursja zatrzymuje się, gdy pozostaniemy
z punktami ograniczonymi do ich ostatniej współrzędnej.
Idea algorytmu zapytań
◮ Używamy drzew pierwszego poziomu do wyznaczenia O(log n) węzłów, których
kanoniczne podzbiory łącznie zawierają wszystkie punkty, których współrzędne
są we właściwym przedziale.
◮ W stosunku do kanonicznych podzbiorów zadawane są dalej zapytania o od-
powiedni obszar w odpowiadajacych im strukturach drugiego poziomu;
◮ W każdej takiej strukturze wybranych zostaje O(log n) kanonicznych pod-
zbiorów. Tym samym, mamy w sumie O(log2 n) kanonicznych podzbiorów
w strukturach drugiego poziomu, które łacznie zawierają wszystkie punkty,
których pierwsze i drugie współrzędne leżą we właściwym obszarze.
◮ Następnie struktury trzeciego poziomu przechowujące te kanoniczne podzbiory
są pytane o obszar dla trzeciej współrzędnej, itd., aż dotrzemy do drzew jed-
nowymiarowych.
Idea algorytmu zapytań
◮ Używamy drzew pierwszego poziomu do wyznaczenia O(log n) węzłów, których
kanoniczne podzbiory łącznie zawierają wszystkie punkty, których współrzędne
są we właściwym przedziale.
◮ W stosunku do kanonicznych podzbiorów zadawane są dalej zapytania o od-
powiedni obszar w odpowiadajacych im strukturach drugiego poziomu;
◮ W każdej takiej strukturze wybranych zostaje O(log n) kanonicznych pod-
zbiorów. Tym samym, mamy w sumie O(log2 n) kanonicznych podzbiorów
w strukturach drugiego poziomu, które łacznie zawierają wszystkie punkty,
których pierwsze i drugie współrzędne leżą we właściwym obszarze.
◮ Następnie struktury trzeciego poziomu przechowujące te kanoniczne podzbiory
są pytane o obszar dla trzeciej współrzędnej, itd., aż dotrzemy do drzew jed-
nowymiarowych.
Twierdzenie 3.9. (m.in. Bentley, 1979; Lueker, 1978)
Niech S będzie zbiorem n punktów w d-wymiarowej przestrzeni Rd, d ≥ 2. Wów-
czas drzewo obszarów dla S używa O(n logd−1 n) pamięci i może być zbudowane w
czasie O(n logd−1 n). Punkty S leżące w prostokątnym obszarze zapytania można
wyznaczyć w czasie O(logd n + k), gdzie k jest liczbą zgłaszanych punktów.
◮ Kaskadowanie cząstkowe: czas zapytania rzędu O(logd−1 n + k).
3.5 Drzewa przeszukiwań priorytetowych
Zastosowanie przy zapytaniach o dwuwymiarowy obszar ortogonalny R, z którego
jeden brzeg jest nieograniczony, tj. gdy R = (−∞, x2) × [y1, y2].

(−∞, x2 ] × [y1 , y2 ]
3.5 Drzewa przeszukiwań priorytetowych
Zastosowanie przy zapytaniach o dwuwymiarowy obszar ortogonalny R, z którego
jeden brzeg jest nieograniczony, tj. gdy R = (−∞, x2) × [y1, y2].
Kopiec jednowymiarowy
1

3 8

11 4 15 21

36 32

◮ Kopiec jest drzewem binarnym, w którym korzeń pamięta punkt ze zbioru o


minimalnym kluczu (wartości).
◮ Reszta zbioru jest podzielona na dwa podzbiory o prawie równym rozmiarze i
te podzbiory pamiętywane są rekurencyjnie w ten sam sposób.
Obserwacja. Zapytanie o jednowymiarowy obszar (−∞, x2] można wykonać w
czasie rzędu rzędu O(1 + k), gdzie k jest liczbą zgłaszanych punktów.
3.5 Drzewa przeszukiwań priorytetowych
Zastosowanie przy zapytaniach o dwuwymiarowy obszar ortogonalny R, z którego
jeden brzeg jest nieograniczony, tj. gdy R = (−∞, x2) × [y1, y2].
Kopiec jednowymiarowy
1

3 8

11 4 15 21

36 32

◮ Kopiec jest drzewem binarnym, w którym korzeń pamięta punkt ze zbioru o


minimalnym kluczu (wartości).
◮ Reszta zbioru jest podzielona na dwa podzbiory o prawie równym rozmiarze i
te podzbiory pamiętywane są rekurencyjnie w ten sam sposób.
Obserwacja. Zapytanie o jednowymiarowy obszar (−∞, x2] można wykonać w
czasie rzędu rzędu O(1 + k), gdzie k jest liczbą zgłaszanych punktów.
Idea algorytmu zapytania w kopcu jednowymiarowym

◮ Odwiedzanie węzłów drzewa w głąb: gdy odwiedzamy węzeł v, sprawdzamy,


czy jego wartość leży w przedziale (−∞, x2].
Jeśli tak, to podajemy punkt i kontynuujemy przeszukiwanie w obu sy-

nach węzła v. W przeciwnym razie przerywamy przeszukiwanie w tej części
drzewa.

3 8

11 4 15 21

36 32

Przykład. Poszukujemy punktów z przedziału (−∞, 5] w powyższym drzewie.


Wówczas odwiedzamy i podajemy węzły/punkty 1, 3 oraz 4; odwiedzamy także
węzły 8 i 11, ale w nich przeszukiwanie zostaje przerwane.
Drzewo przeszukiwań priorytetowych

p5
p1
p2
p2
p1
p5
p4 p4
p6
p3
p3
p6

Ilustracja idei.
◮ Punkt p5 ma najmniejszą współrzędną x − zatem stanowi on korzeń drzewa.
◮ Pozostałe punkty dzielone są „na pół” względem współrzędnej y.
Punkty p3, p4 i p6 mają mniejszą współrzędną y od punktów p1 i p2. Pamię-

tane są w dolnym (lewym) poddrzewie, którego korzeniem jest p3 − punkt
ten ma najmniejszą współrzędną x spośród punktów p3, p4 i p6.
Punkty p1 i p2 pamiętane są w górnym (prawym) poddrzewie, którego ko-

rzeniem jest p1 (x(p1) < x(p2)).
p5
p1
p2
p2
p1
p5
p4 p4
p6
p3
p3
p6

Drzewo przeszukiwań priorytetowych dla zbioru punktów S.


(Zakładamy, że wszystkie punkty mają różne współrzędne.)
◮ Jeśli S = ∅, to drzewo przeszukiwań binarnych jest pustym liściem.
◮ W przeciwnym przypadku, niech pmin będzie punktem w zbiorze S o naj-
mniejszej współrzędnej x. Niech ymed będzie medianą współrzędnych y pozo-
stałych punktów i niech
a Sponiżej := {p ∈ S \ {pmin} : y(p) ≤ ymed}
a oraz Spowyżej := {p ∈ S \ {pmin} : y(p) > ymed}.
Drzewo przeszukiwań priorytetowych składa się z korzenia v, w którym są pa-
miętane punkt p(v) := pmin oraz wartość y(v) := ymed, lewe poddrzewo v jest
drzewem przeszukiwań priorytetowych dla zbioru Sponiżej, a prawe poddrzewo
jest drzewem przeszukiwań priorytetowych dla Spowyżej.
Czas konstrukcji: O(n log n).
Idea algorytmu zapytań dla obszaru (−∞, x2] × [y1, y2]
◮ Poszukujemy w drzewie wartości y1 i y2. Interesują nas węzły na ścieżkach po-
szukiwań π1 i π2 wartości y1 i y2, a także poddrzewa pomiędzy tymi ścieżkami.
Dla każdego z węzła v na ścieżkach

poszukiwań y1 i y2 sprawdzamy, czy
odpowiadający mu punkt p(v) należy v
dziel

do obszaru zapytania.
Dla każdego poddrzewa T pomiędzy

ścieżkami π1 i π2 wywołujemy poniższą y1
procedurę ReportInSubtree.
Rzędne punktów przechowywanych w T
należą do przedziału [y1, y2], zatem wy- y2

starczy sprawdzić tylko odciętą tych


punktów.
Idea algorytmu zapytań dla obszaru (−∞, x2] × [y1, y2]
◮ Poszukujemy w drzewie wartości y1 i y2. Interesują nas węzły na ścieżkach po-
szukiwań π1 i π2 wartości y1 i y2, a także poddrzewa pomiędzy tymi ścieżkami.
Dla każdego z węzła v na ścieżkach

poszukiwań y1 i y2 sprawdzamy, czy
odpowiadający mu punkt p(v) należy v
dziel

do obszaru zapytania.
Dla każdego poddrzewa T pomiędzy

ścieżkami π1 i π2 wywołujemy poniższą y1
procedurę ReportInSubtree.
Rzędne punktów przechowywanych w T
należą do przedziału [y1, y2], zatem wy- y2

starczy sprawdzić tylko odciętą tych


punktów.
Idea algorytmu zapytań dla obszaru (−∞, x2] × [y1, y2]
◮ Poszukujemy w drzewie wartości y1 i y2. Interesują nas węzły na ścieżkach po-
szukiwań π1 i π2 wartości y1 i y2, a także poddrzewa pomiędzy tymi ścieżkami.
Dla każdego z węzła v na ścieżkach

poszukiwań y1 i y2 sprawdzamy, czy
odpowiadający mu punkt p(v) należy v
dziel

do obszaru zapytania.
Dla każdego poddrzewa T pomiędzy

ścieżkami π1 i π2 wywołujemy poniższą y1
procedurę ReportInSubtree.
Rzędne punktów przechowywanych w T
y2
należą do przedziałux [y1 , y2 ], zatem wy-
ReportInSubtree(v, 2)
starczy sprawdzić tylko odciętą tych
Wejście. Korzeń poddrzewa przeszukiwań priotytetowych i wartość x2.
punktów.
Wyjście. Wszystkie punkty w poddrzewie o odciętej nie większej od x2.
1. if v 6= null oraz x(p(v)) ≤ x2
2. then Podaj p(v).
3. then ReportInSubtree(lewy-syn(v), x2)
4. then ReportInSubtree(prawy-syn(v), x2)
Lemat 3.10. Procedura ReportInSubtree(v, x2) podaje w czasie rzędu
O(1 + kv ) wszystkie punkty w poddrzewie zakorzenionym w węźle v, których od-
cięta jest nie większa od x2, gdzie kv jest liczbą podawanych punktów.

◮ Zgłoszone zostają wszystkie i tylko te punkty, które leżą w obszarze zapytania.

x(rodzic(w)) ≤ x2

◮ Złożoność czasowa procedury.


Gdy odwiedzamy węzeł w 6= v, musieliśmy wcześniej podać punkt pamię-

tany przez jego rodzica.
Liczba odwiedzonych węzłów w 6= v jest nie większa niż podwojona liczba

zgłoszonych punktów, a zatem jest ona rzędu O(kv ).
W konsekwencji otrzymujemy O(1 + kv ).

Lemat 3.11.
Algorytm podaje wszystkie punkty z obszaru zapytania (−∞, x2] × [y1, y2] w czasie
rzędu O(h + k), gdzie h jest głębokością drzewa, a k liczbą podawanych punktów.

vdziel

y1

y2

◮ Należy wykazać, że każdy punkt zgłaszany przez algorytm leży w obszarze za-
pytania.
Węzły leżące na ścieżkach π1 i π2 poszukiwań y1 oraz y2 są sprawdzane

bezpośrednio, czy leżą w obszarze zapytania.
Węzły leżące w poddrzewach pomiędzy ścieżkami π1 i π2 . . .

vdziel

y1

y2

Rozważmy wywołanie ReportInSubtree(prawy-syn(w), x2) dla pewnego


węzła w. Niech p będzie dowolnym zgłaszanym punktem.
⊲ Z kształtu procedury ReportInSubtree otrzymujemy, że x(p) ≤ x2.
⊲ Jako że wszystkie węzły odwiedzane w tym wywołaniu leżą na lewo od vdziel
i y(vdziel) < y2, zachodzi y(p) < y2.
⊲ Wszystkie węzły odwiedzane w tym wywołaniu leżą na prawo od v i ścieżka
poszukiwania y1 szła w lewo w v, zatem zachodzi y1 ≤ y(p).
⊲ A zatem p ∈ (−∞, x2] × [y1, y2]).
Analogicznie możemy rozważyć wywołanie ReportInSubtree(lewy-syn(u), x2)
dla pewnego węzła u.
vdziel

y1

y2

◮ Należy wykazać, że każdy punkt p z obszaru zapytania zostanie zgłoszony.


Punkt p musi znajdować się albo w węźle na ścieżkach poszukiwań y1 i y2

lub w jednym z poddrzew pomiędzy tymi ścieżkami.
vdziel

y1

y2

◮ Należy wykazać, że każdy punkt p z obszaru zapytania zostanie zgłoszony.


Punkt p musi znajdować się albo w węźle na ścieżkach poszukiwań y1 i y2

lub w jednym z poddrzew pomiędzy tymi ścieżkami.
◮ Złożoność czasowa.
Czas liniowy względem liczby węzłów na ścieżkach poszukiwań y1 oraz y2.


Głębokość drzewa wynosi h, a zatem całkowita liczba węzłów na ścieżkach



poszukiwań jest rzędu O(h).
W konsekwencji, mając na uwadze lemat 4.10, czas wymagany przez wszyst-

kie wywołania ReportInSubtree jest rzędu O(h + k).
vdziel

y1

y2

Jako że dla zbioru n punktów na płaszczyźnie drzewo przeszukiwań priorytetowych


jest drzewem binarnym o głębokości O(log n) i wykorzystywanej pamięci rzędu
O(n), otrzymujemy następujące twierdzenie.

Twierdzenie 3.12. (McCreight 1985)


Drzewo przeszukiwań priorytetowych dla zbioru n punktów na płaszczyźnie, które
używa O(n) pamięci, można zbudować w czasie O(n log n). Wykorzystując to
drzewo można podać wszystkie punkty z obszaru zapytania (−∞, x2] × [y1, y2] w
czasie O(log n + k), gdzie k jest liczbą podawanych punktów.
3.6 Ogólny zbiór punktów
Niech a|b oznacza liczbę złożoną z dwóch liczb rzeczywistych a i b. Zdefiniujmy
następujący porządek leksykograficzny: dla dwóch liczb złożonych (a|b) i (a′|b′)
zachodzi
(a|b) < (a′|b′) ⇔ a < a′ lub (a = a′ i b < b′).

Załóżmy, że mamy dany zbiór S zawierający n różnych punktów na płaszczyźnie.


Rozważmy zbiór S ′ określony następująco:

S ′ = {((px|py ), (py |px)) : (px, py ) ∈ S}.

Jako że punkty w S są różne, pierwsze współrzędne dowolnych punktów z S ′ są


także różne; to samo pozostaje prawdą dla drugiej współrzędnej. Przekształćmy
teraz obszar zapytania R = [x1, x2] × [y1, y2] w obszar R′ następująco:

R′ = [(x1| − ∞), (x2| + ∞)] × [(y1| − ∞), (y2| + ∞)].

Lemat 3.13. Zachodzi p ∈ R ⇔ p′ ∈ R′.


3.6 Ogólny zbiór punktów
Niech a|b oznacza liczbę złożoną z dwóch liczb rzeczywistych a i b. Zdefiniujmy
następujący porządek leksykograficzny: dla dwóch liczb złożonych (a|b) i (a′|b′)
zachodzi
(a|b) < (a′|b′) ⇔ a < a′ lub (a = a′ i b < b′).

Załóżmy, że mamy dany zbiór S zawierający n różnych punktów na płaszczyźnie.


Rozważmy zbiór S ′ określony następująco:

S ′ = {((px|py ), (py |px)) : (px, py ) ∈ S}.

Jako że punkty w S są różne, pierwsze współrzędne dowolnych punktów z S ′ są


także różne; to samo pozostaje prawdą dla drugiej współrzędnej. Przekształćmy
teraz obszar zapytania R = [x1, x2] × [y1, y2] w obszar R′ następująco:

R′ = [(x1| − ∞), (x2| + ∞)] × [(y1| − ∞), (y2| + ∞)].

Lemat 3.13. Zachodzi p ∈ R ⇔ p′ ∈ R′.


3.6 Ogólny zbiór punktów
Niech a|b oznacza liczbę złożoną z dwóch liczb rzeczywistych a i b. Zdefiniujmy
następujący porządek leksykograficzny: dla dwóch liczb złożonych (a|b) i (a′|b′)
zachodzi
(a|b) < (a′|b′) ⇔ a < a′ lub (a = a′ i b < b′).

Załóżmy, że mamy dany zbiór S zawierający n różnych punktów na płaszczyźnie.


Rozważmy zbiór S ′ określony następująco:

S ′ = {((px|py ), (py |px)) : (px, py ) ∈ S}.

Jako że punkty w S są różne, pierwsze współrzędne dowolnych punktów z S ′ są


także różne; to samo pozostaje prawdą dla drugiej współrzędnej. Przekształćmy
teraz obszar zapytania R = [x1, x2] × [y1, y2] w obszar R′ następująco:

R′ = [(x1| − ∞), (x2| + ∞)] × [(y1| − ∞), (y2| + ∞)].

Lemat 3.13. Zachodzi p ∈ R ⇔ p′ ∈ R′.


BuildKdTree(S, d)
Wejście. Zbiór punktów S i aktualna głębokość d.
Wyjście. Korzeń kd-drzewa przechowującego zbiór S.
1. if S zawiera tylko jeden punkt
2. then return liść pamiętający ten punkt
3. else if d jest parzyste
4. then Podziel S na dwa zbiory S1 i S2 pionową prostą l przechodzącą przez medianę
then współrzędnych x punktów z S, gdzie S1 zawiera punkty na lewo lub na prostej l,
then a S2 zawiera punkty na prawo od prostej l.
5. else Podziel S na dwa zbiory S1 i S2 poziomą prostą l przechodzącą przez medianę
then współrzędnych y punktów z S, gdzie S1 zawiera punkty poniżej lub na prostej l,
then a S2 zawiera punkty powyżej prostej l.
6. else lewy-syn(v) := BuildKdTree(S1, d + 1);
7. else prawy-syn(v) := BuildKdTree(S2 , d + 1);
8. else Stwórz wierzchołek v pamietający prostą l, uczyń vlewy i vprawy jego lewym
else i prawym dzieckiem, odpowiednio.
9. return v.
KdTreeQuery(v, R)
Wejście. Korzeń kd-(pod)drzewa oraz obszar zapytania R.
Wyjście. Wszystkie punkty w liściach poniżej v, które leżą w obszarze R.
1. if v jest liściem
2. then Podaj punkt p pamiętany w v, o ile p ∈ R.
3. else if obszar(lewy-syn(v)) jest całkowicie zawarty w R
4. then ReportSubtree(lewy-syn(v))
5. else if obszar(lewy-syn(v)) przecina R
6. then KdTreeQuery(lewy-syn(v), R)
7. else if obszar(prawy-syn(v)) jest całkowicie zawarty w R
8. then ReportSubtree(prawy-syn(v))
9. else if obszar(prawy-syn(v)) przecina R
10. then KdTreeQuery(prawy-syn(v), R)

ReportSubtree jest procedurą, która przechodzi poddrzewo zakorzenione w danym węźle i wylicza wszystkie
punkty pamiętane w jego liściach.
FindSplitNode(T , x1, x2)
Wejście. Drzewo T i dwie wartości x1, x2 ∈ R, x1 ≤ x2.
Wyjście. Węzeł vdziel , w którym rozchodzą się ścieżki w poszukiwaniu x1 i x2;
Wyjście. lub liść, w którym obie ścieżki kończą się.
1. v := korzeń(T );
2. while v nie jest liściem oraz (x2 ≤ klucz(v) lub x1 > klucz(v)) do
2.1 if x2 ≤ klucz(v) then v := lewy-syn(v);
2.2 else v := prawy-syn(v);
3. Zwróć v.
1DRangeQuery(T , [x1, x2])
Wejście. Drzewo T i przedział [x1, x2].
Wyjście. Wszystkie punkty z T , które leżą w przedziale [x1, x2].
1. vdziel := FindSplitNode(T , x1, x2);
2. if vdziel jest liściem
3. then Sprawdź, czy klucz(vdziel) musi być podany (∈ [x1, x2]).
4. else /* Idź ścieżką do l1 i wyliczaj punkty w poddrzewach na prawo od ścieżki.*/
5. v := lewy-syn(vdziel);
6. while v nie jest liściem do
7. if x1 ≤ klucz(v)
8. then ReportSubtree(prawy-syn(v));
9. then v := lewy-syn(v);
10. else v := prawy-syn(v);
11. Sprawdź, czy punkt pamiętany w liściu v (= l1) musi być podany.
12. Analogiczne postępowanie dla ścieżki poszukiwań x2:
− wylicz punkty w poddrzewach na lewo od ścieżki;
− sprawdź, czy wartość na końcu ścieżki (liść) musi być podana.
2DRangeQuery(T , [x1, x2] × [y1 , y2])
Wejście. Dwuwymiarowe drzewo obszarów T i obszar [x1, x2] × [y1 , y2].
Wyjście. Wszystkie punkty z T , które leżą w obszarze zapytania.
1. vdziel := FindSplitNode(T , x1, x2);
2. if vdziel jest liściem
3. then Sprawdź, czy punkt pamietany w vdziel musi być podany.
4. else /* Idź ścieżką w poszukiwaniu x1 i wywołuj 1DRangeQuery
dla poddrzew stowarzyszonych na prawo od ścieżki.*/
5. v := lewy-syn(vdziel);
6. while v nie jest liściem do
7. if x1 ≤ klucz(v)
8. then 1DRangeQuery(Tstow (prawy-syn(v)), [y1, y2]);
9. then v := lewy-syn(v);
10. else v := prawy-syn(v);
11. Sprawdź, czy punkt pamiętany w liściu v musi być podany.
12. Analogiczne postępowanie dla ścieżki poszukiwań x2.
/* Idź ścieżką w poszukiwaniu x2 i wywołuj 1DRangeQuery dla poddrzew stowarzyszonych
na lewo od ścieżki i sprawdź, czy punkt pamiętany na końcu ścieżki musi być podany. */
QuerySearchTree(T , (−∞, x2] × [y1, y2])
Wejście. Korzeń drzewa przeszukiwań priotytetowych i obszar zapytania.
Wyjście. Wszystkie punkty w obszarze zapytania.
1. Wyszukaj y1 oraz y2 w kopcu T . Niech vdziel będzie węzłem, w którym ścieżki poszukiwań y1 oraz y2 rozchodzą
się, i niech v1 oraz v2 będą węzłami, w których skończyło się przeszukiwanie odpowiednio y1 oraz y2 . (Jeśli w
drzewie brak jest którejś z wartości, to odpowiedni wierzchołek końcowy ścieżki jest liściem).
2. for każdy węzeł v na ścieżce poszukiwań y1 oraz y2 do
3. if p(v) ∈ (−∞, x2] × [y1, y2]) then podaj p(v)
4. for każdy węzeł v na ścieżce z vdziel do v1 do
5. if w węźle v ścieżka poszukiwania y1 idzie w lewo
6. then ReportInSubtree(prawy-syn(v), x2)
7. for każdy węzeł v na ścieżce z vdziel do v2 do
8. if w węźle v ścieżka poszukiwania y2 idzie w prawo
9. then ReportInSubtree(lewy-syn(v), x2)

You might also like