background image

 

 

1

Algorytmy i 
struktury 
danych

Wykład 6
Drzewa

background image

 

 

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. 

background image

 

 

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. 

background image

 

 

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!).

background image

 

 

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ł.

background image

 

 

6

Przykład wstawiania 
(wstawiamy 23)

background image

 

 

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.

background image

 

 

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.

background image

 

 

9

Przykłady wyszukiwań

Niebieska strzałka to poszukiwanie 13 
(znaleziono), czerwona to poszukiwanie 22 (nie 
ma w drzewie).

background image

 

 

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.

background image

 

 

11

Poszukiwanie maksimum 
(czerwone) i minimum 
(niebieskie)

background image

 

 

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.

background image

 

 

13

Usuwanie: przypadek 1 - 
usuwany węzeł nie ma 
potomstwa

Usuwamy element (zwalniamy pamięć)

Rodzic usuniętego ma teraz wskazywać na 
NULL.

background image

 

 

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.

background image

 

 

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).

background image

 

 

16

Usuwanie, przypadek 3: 

Zamiana

background image

 

 

17

Usuwanie, przypadek 3: 
Usunięcie żądanego elementu

background image

 

 

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

background image

 

 

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.

background image

 

 

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

background image

 

 

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.

background image

 

 

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). 

background image

 

 

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.

background image

 

 

24

Przykład przechodzenia drzewa 
wszerz

background image

 

 

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.

background image

 

 

26

Przykład drzewa 
zrównoważonego

background image

 

 

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

 (

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.

background image

 

 

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.

background image

 

 

29

Pseudokod równoważenia 
tablicą

background image

 

 

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. 

background image

 

 

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ół.

background image

 

 

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.

background image

 

 

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).

background image

 

 

34

I ostatni obrót, uczestniczy w nim 10 i 8.

background image

 

 

35

„Drzewo” ma teraz postać listy.

background image

 

 

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). 

background image

 

 

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 ( 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: 

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.

background image

 

 

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.

background image

 

 

39

background image

 

 

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.

background image

 

 

41

Kolejny przykład równoważenia 
algorytmem DSW

background image

 

 

42

background image

 

 

43

background image

 

 

44

background image

 

 

45

background image

 

 

46

background image

 

 

47

background image

 

 

48

background image

 

 

49


Document Outline