1
Algorytmy i
struktury
danych
Wykład 6
Drzewa
2
Definicja drzewa
Drzewo to struktura umożliwiająca
przechowywanie danych zbudowana z
węzłów oraz wskaźników do potomków.
Drzewa rysuje się w sposób odwrotny,
niż rosną one w przyrodzie. Na szczycie
struktury znajduje się korzeń – węzeł nie
mający ojca, a na samym dole
umiejscowione są liście - nie
posiadające synów.
3
Drzewa binarne
Odmianą drzew są drzewa binarne. Są to
struktury, w których każdy węzeł posiada co
najwyżej dwóch synów – lewego i prawego.
Rozmieszczenie elementów w drzewie nie
jest przypadkowe. Wszystkie elementy
znajdujące się w lewym poddrzewie są
mniejsze od swojego ojca, natomiast
elementy prawego poddrzewa są większe
od ojca. Reguła ta obowiązuje wszystkie
poddrzewa.
4
Np. wszystkie elementy lewego
poddrzewa piętnastki są mniejsze od
niej, a wszystkie elementy prawego są
od niej większe (inaczej niż w kopcu!).
5
Dodawanie elementu
Aby wstawić nowy element do drzewa należy
począwszy od korzenia porównywać dany
element z węzłem i jeżeli jest on mniejszy od
wartości przechowywanej w tym węźle to
poruszać się w lewo po drzewie, w
przeciwnym wypadku poruszać się w prawo.
Wędrujemy tak długo, aż dojdziemy do
miejsca, w którym napotkany wskaźnik do
potomka w węźle będzie wskazywał na NULL
(co oznacza, że niżej nic nie ma).
Wtedy wstawiamy nowy węzeł w to miejsce,
a wspomniany wskaźnik ustawiamy tak, aby
wskazywał na nowy węzeł.
6
Przykład wstawiania
(wstawiamy 23)
7
Wyszukiwanie elementu
Przeszukiwanie drzewa binarnego jest
bardzo podobne do wstawiania.
Rozpoczynając od korzenia porównujemy
wartość napotkanego węzła z szukaną
liczbą. Gdy to nie jest szukany element
to, jeśli szukana liczba jest mniejsza od
tej przechowywanej w węźle to idziemy
w lewo, w przeciwnym wypadku
poruszamy się w prawo.
Pomijanie podczas przeszukiwania
niektórych poddrzew możliwe jest dzięki
wspomnianemu specjalnemu
rozmieszczeniu elementów w drzewie.
8
Jeżeli przejdziemy całe drzewo
(natkniemy się na NULL) i żadna
napotkana wartość nie
odpowiadała naszej liczbie, to
oznacza to, że liczby nie ma w
szukanym węźle.
9
Przykłady wyszukiwań
Niebieska strzałka to poszukiwanie 13
(znaleziono), czerwona to poszukiwanie 22 (nie
ma w drzewie).
10
Element minimalny i
maksymalny
Jeżeli chcemy znaleźć element minimalny
(maksymalny) w drzewie to poruszamy
się maksymalnie w lewo (prawo).
Specyficzne rozmieszczenie elementów w
drzewie sprawia, że element minimalny
znajduje się zawsze w najbardziej
„wysuniętym na lewo” węźle, a element
maksymalny w najbardziej „wysuniętym
na prawo” węźle drzewa.
11
Poszukiwanie maksimum
(czerwone) i minimum
(niebieskie)
12
Usuwanie elementu
Przy usuwaniu elementu możliwe są 3
przypadki:
1.
usuwany węzeł nie ma potomstwa.
2.
usuwany węzeł posiada jednego
potomka.
3.
usuwany węzeł posiada aż dwóch
potomków.
13
Usuwanie: przypadek 1 -
usuwany węzeł nie ma
potomstwa
Usuwamy element (zwalniamy pamięć)
Rodzic usuniętego ma teraz wskazywać na
NULL.
14
Usuwanie: przypadek 2 -
usuwany węzeł ma jednego
potomka
Zwalniamy pamięć
Rodzic usuwanego elementu ma wskazywać zamiast
na usuwany element na jego (jedynego) potomka.
15
Usuwanie: przypadek 3 -
usuwany węzeł ma dwóch
potomków
zamieniamy wartość do usunięcia z wartością
minimalną w prawym poddrzewie usuwanego węzła
(na rysunku otoczone przerywaną linią) lub z
wartością maksymalną w lewym poddrzewie.
Następnie usuwamy żądany element (aktualnie
będzie on minimalnym w prawym poddrzewie lub
maksymalnym w lewym poddrzewie).
16
Usuwanie, przypadek 3:
Zamiana
17
Usuwanie, przypadek 3:
Usunięcie żądanego elementu
18
Przechodzenie drzewa w
głąb i wszerz
Aby wypisać elementy znajdujące
się w drzewie można skorzystać z
jednej z dwóch metod
przechodzenia drzewa:
1. w głąb
2. wszerz
19
Przechodzenie w głąb
Pierwsza z nich to metoda zrealizowana
rekurencyjnie. Najpierw zostanie wypisane
lewe poddrzewo, a następnie prawe.
Istnieje sześć metod realizacji tego
wypisywania. Różnią się one kolejnością
wykonywanych operacji. Jeżeli wypisywanie to
jest realizowane rekurencyjnie to należy
wykonać trzy operacje: wypisać węzeł,
wywołać funkcję dla lewego potomka,
wywołać funkcję dla prawego potomka.
Kolejność wykonania tych operacji będzie
decydowała o sposobie wypisania danych.
20
Sześć metod wypisywania w
głąb
Sześć metod wypisywania
(W- wypisz węzeł,
P- wywołaj funkcję dla prawego syna,
L – wywołaj funkcję dla lewego syna):
WLP
WPL
LWP
PWL
LPW
PLW
21
LWP - wypisze wartości z drzewa
rosnąco,
PWL - wypisze wartości z drzewa
malejąco.
Jest to zgodne z zasadami, z jakimi
wywoływana jest rekurencja.
22
Przechodzenie wszerz
Elementy będą wypisywane
poziomami.
Najpierw zostaną wypisane elementy
z najwyższego poziomu (korzeń),
potem kolejnego, a na końcu z
najniższego poziomu (liście w
niezrównoważonym drzewie mogą się
znajdować na różnych poziomach).
23
Do przechodzenia wszerz wykorzystujemy
kolejkę. Na początku wrzucamy do kolejki
korzeń. Następnie wyciągamy korzeń
(wypisujemy go) z kolejki, a wstawiamy do
niej potomstwo korzenia.
Czynność wyciągania węzła z kolejki i
wrzucania jego potomstwa powtarzamy
dopóty, dopóki w kolejce coś się znajduje.
Jeśli wyciągany element nie posiada
potomstwa to do kolejki nic nie zostanie
dodane.
24
Przykład przechodzenia drzewa
wszerz
25
Drzewo zrównoważone
Drzewo zrównoważone to takie,
które ma maksymalnie wypełnione
wszystkie poziomy z wyjątkiem
ewentualnie ostatniego. Tam
elementy są rozlokowane od lewej
strony, ale niekoniecznie
wypełniają cały poziom.
26
Przykład drzewa
zrównoważonego
27
Korzyść ze zrównoważenia
drzewa
Drzewo zrównoważone umożliwia znacznie szybsze
jego przeszukiwanie.
W najgorszym przypadku nasze drzewo mogło by
mieć kształt listy. Wtedy, aby przeszukać taką
strukturę należy sprawdzić wszystkie n węzłów
drzewa.
W najlepszej sytuacji, gdy drzewo będzie idealnie
zrównoważone wystarczy sprawdzić log
2
(n
węzłów.
Nietrudno zauważyć, że różnica w ilości porównań
jest znaczna, np. dla 10 000 elementów w
najgorszym przypadku należałoby sprawdzić
właśnie 10 000 węzłów, a w najlepszym jedynie 14.
28
Równoważenie drzewa –
Metoda z wykorzystaniem
pomocniczej tablicy
Najpierw wykorzystując metodę przechodzenia
drzewa w głąb zrzucamy wszystkie elementy
drzewa do tablicy. Musi to być metoda LWP
(elementy muszą być posortowane rosnąco).
Następnie, wykorzystując rekurencję,
dodajemy elementy do drzewa. Robimy to w
taki sposób, że dodajemy element środkowy
tablicy, a następnie wywołujemy funkcje dodaj
dla lewej części tablicy i prawej części.
Nasza funkcja będzie miała dwa argumenty –
lewy i prawy indeks tablicy. Pierwsze
wywołanie funkcji nastąpi dla całej tablicy.
29
Pseudokod równoważenia
tablicą
30
Równoważenie drzewa:
Algorytm DSW
Metoda ta nie wymaga użycia
dodatkowej tablicy.
Polega ona na obracaniu drzewa w
prawo (lewo) aż do uzyskania listy, a
następnie obracaniu go w lewo (prawo),
aż do uzyskania drzewa
zrównoważonego.
Podczas tych operacji obowiązują
pewne zasady.
31
Przykład równoważenia
przez DSW, Etap 1 –
obracanie w prawo
Lewy syn korzenia staje się korzeniem, a
prawe potomstwo tego syna staje się
lewym potomstwem dawnego korzenia,
który wędruje w dół.
32
Dokonujemy tego tak długo, aż
korzeń nie będzie miał lewego
syna, a następnie to samo robimy
dla wszystkich prawych potomków.
33
Korzeń nie ma już lewego syna, wykonujemy
obrót dla pierwszego prawego potomka, który
posiada lewego syna (jest to 10). Prawe
poddrzewo węzła, który idzie w gorę (siódemki)
jest przyczepiane jako lewe poddrzewo węzła,
który idzie w dół (dziesiątki).
34
I ostatni obrót, uczestniczy w nim 10 i 8.
35
„Drzewo” ma teraz postać listy.
36
Etap 2 równoważenia DSW,
obracanie w lewo
Teraz wykonujemy obroty w lewo (przeciwnie
do ruchu wskazówek zegara).
Obroty te wykonujemy wg określonych zasad.
Począwszy od korzenia, co drugi element
staje się lewym synem swojego prawego
potomka. Dodatkowo należy pamiętać, o
ilości wykonywanych obrotów. Najpierw
wykonujemy ich tyle, ile wynosi różnica
pomiędzy ilością elementów w naszym
drzewie (n), a ilością elementów w
najbliższym drzewie pełnym o liczbie
elementów mniejszej od naszego drzewa (m).
37
Drzewa pełne to takie, które mają wszystkie
poziomy zapełnione maksymalnie.
Ilość węzłów w takim drzewie to 2
k
- , gdzie k
to liczba poziomów ( k C). Jeżeli nasze
drzewo jest drzewem niepełnym o liczbie
węzłów równej n to ilość węzłów w najbliższym
pełnym drzewie (mającym mniej węzłów niż n)
będzie obliczana z wzoru:
m 2
log2 (n
1)
1. A więc najpierw wykonujemy
t = n - m obrotów a następnie wykonujemy ich
w każdym cyklu t/2 obrotów dopóty, dopóki
t>0.
38
Dla naszego przykładu n wynosi 6,
więc najbliższe pełne drzewo (o liczbie
elementów nie większej od naszego
drzewa) to drzewo, które ma (2
2
– 1)
=3 elementy. Dlatego najpierw
wykonujemy 6-3=3 obrotów węzłów
nadmiarowych (tych, które znajdą się
na ostatnim poziomie). W naszym
przypadku obracamy 3, 7 i 10.
39
40
Teraz wykonujemy kolejne obroty w
liczbie 3/2=1, dla co drugiego węzła
począwszy od korzenia (czyli tylko dla
5).
Na tym kończymy
gdyż ilość
obrotów (1/2 = 0)
jest równa zero.
Nasze drzewo
zostało
zrównoważone.
41
Kolejny przykład równoważenia
algorytmem DSW
42
43
44
45
46
47
48
49