Lekcja 8
drzewa, obchody drzew
Listy c.d.
Zadanie 120
Zaimplementuj następujące operacje na listach jednokierunkowych:
- Konkatenacja(L1, L2, var L3)
czyli połączenie list L1 i L2 oraz umieszczenie wyniku w L3; wynik ma
zawierać kopię elementów, nowy element listy tworzymy procedurą
x<-nowyElement
- OdwrócKolejność(var L)
odwracamy kolejność elementów listy; w tym wypadku nie tworzy się
kopii elementów
- Długość(L)
oblicza długość listy; koniecznie użyj rekurencji!
- Szukaj(L, wartość)
szuka na liście elementu o podanej wartości i zwraca wskazanie na ten
element, jeśli takiego elementu nie ma to zwraca nil; koniecznie użyj
rekurencji!
Drzewa binarne.
Drzewo binarne składa się z elementów (obiektów) z których każdy posiada
atrybuty: wartość, lewy, prawy, przy czym lewy i prawy
wskazują na lewego i prawego "potomka" ...
Drzewo
reprezentujemy przez obiekt D z atrybutem korzeń. Wartości nil
w atrybutach lewy i prawy są wykorzystywane w następujący
sposób:
Zadanie
121
Zaimplementuj następujące operacje na drzewie binarnym:
- WypiszMetodąPreOrder(D)
metoda PreOrder to rekurencyjna metoda wypisywania wartości
elementów drzewa polegająca na tym że:
a. wypisujemy wartość korzenia,
b. wypisujemy wartości lewego poddrzewa,
c. wypisujemy wartości prawego poddrzewa.
- WypiszMetodąInOrder(D)
w tej metodzie wypisywania elementów zamieniamy miejscami (a) i (b)
- Zasymuluj działanie powyższych metod na poniższym drzewie:
- WypiszMetodąWszerz(D)
najpierw wypisujemy korzeń, potem elementu w odległości 1 od
korzenia (1 poziom), potem 2 poziom itd.
Wskazówka: można użyć pomocniczej tablicy której elementami są
wskazania na elementy drzewa.
- Wysokość(D)
procedura wypisuje wysokość drzewa, czyli największą odległość od
korzenia do liścia ...
- wskazanie = Szukaj(D, wartość)
szuka w drzewie elementu o podanej wartości i zwraca wskazanie na
ten element, jeśli takiego elementu nie ma to zwraca nil
- zaimplementuj operację Szukaj(D, wartość) bez
stosowania rekurencji!
Operacje słownikowe.
Przez operacje słownikowe rozumiemy następujące operacje:
- Wstaw
wstawia nowy element (czyli parę: klucz, wartość) do słownika
- Szukaj
sprawdza czy w słowniku znajduje się element o zadanym kluczu, jeśli
tak to zwraca odpowiadającą mu wartość
- Usun
usuwa dany element
Uwaga: prawdziwe zastosowania słownika wymagają aby element
słownika zawierał parę (klucz, wartość); dla prostoty w poniższych
zadaniach będziemy się posługiwać tylko wartością ...
Zadanie 122
Zaimplementuj operacje słownikowe:
- TAB_Wstaw(wartość)
- indeks = TAB_Szukaj(wartość)
jeśli elementu nie ma to zwraca 0 (do przechowywania wartości używamy
tablicy T[1..n])
- TAB_Usun(indeks)
przy pomocy tablicy, tak efektywnie jak to możliwe (chodzi o czas
działania). Oszacuj czas działania tych 3 operacji przyjmując jako
operację dominującą:
a. porównywanie wartości
b. przypisywanie wartości
Drzewa BST.
Drzewa BST to szczególny rodzaj drzew binarnych na których można efektywnie
wykonywać operacje słownikowe ...
Kilka faktów:
- BST = Binary Search Tree
- Każdy wierzchołek x drzewa BST posiada atrybuty:
wartość, lewy, prawy, rodzic
- Drzewo BST to drzewo binarne (niekoniecznie pełne) posiadające następującą
własność:
niech x wskazuje dowolny wierzchołek drzewa;
wszystkie wierzchołki lewego poddrzewa wierz x mają
wartości
< wartość[x]
wszystkie wierzchołki prawego poddrzewa wierz x mają
wartości
> wartość[x]
Przykład drzewa BST:
Założenie: dla uproszczenia zakładamy że wszystkie wartości w drzewie BST są różne
!
Oto podstawowe operacje na drzewie BST:
-
BST_Wstaw(korzeń, nowy)
-
oczywiście nowy wierzchołek należy wstawiać tak aby
nie popsuć własności drzewa BST; nowy wierzchołek wstawiamy zawsze jako liść drzewa,
należy tylko wyszukać odpowiednie miejsce: sprawdzamy czy
wartość[nowy] < wartość[korzen]
jeśli tak to wiemy że wierzchołek zostanie wstawiony w lewym
poddrzewie, w przeciwnym wypadku zostanie wstawiony w prawym poddrzewie itd
-
-
wskazanie = BST_Maksimum(korzen)
-
wystarczy "iść" po prawej gałęzi drzewa BST, w kierunku od korzenia do
liścia, tak długo jak to możliwe
-
-
wskazanie = BST_Następnik(wierzchołek)
-
1) jeśli wierzchołek posiada prawe poddrzewo, to wtedy zwracamy minimalny
element w prawym poddrzewie
-
2) w przeciwnym wypadku szukamy wierzchołka takiego, że największym kluczem jego
lewego poddrzewa jest wartość[wierzchołek]; innymi słowy idziemy od wierzchołka
wskazywanego przez wierzchołek w górę drzewa tak długo aż napotkamy wierzchołek, który jest lewym
synem swojego rodzica; wartość rodzica jest właśnie poszukiwanym następnikiem (na
powyższym rysunku następnikiem 13 jest 15)
- BST_Usuń(wierzchołek)
-
Uwaga: ta procedura jest dość skomplikowana !
należy rozważyć trzy przypadki:
1) wierzchołek jest liściem drzewa - wtedy zwyczajnie go usuwamy
2) wierzchołek ma tylko jednego potomka - wtedy dodajemy połączenie
między rodzic[wierzchołek] i lewy[wierzchołek] (lub prawy[wierzchołek]),
a sam wierzchołek usuwamy
3) wierzchołek ma dwóch potomków - wtedy znajdujemy następnik
wierzchołek; oznaczmy go przez wierzchołekN; o wierzchołekN
wiemy że nie ma lewego potomka; dodajemy połączenie między rodzic[wierzchołekN]
i prawy[wierzchołekN], następnie przepisujemy wartość wierzchołekN
do wartości wierzchołek i usuwamy wierzchołekN.
Trzeci przypadek powyższej procedury jest przedstawiony na poniższym rysunku:
Zadanie 123
Zaimplementuj operacje słownikowe:
- BST_Wstaw(D, nowy)
wstawia element wskazywany przez parametr nowy
- wskazanie = BST_Szukaj(D, wartość)
szuka elementu o podanej wartości;
jeśli elementu nie ma to zwraca nil
- BST_Usuń(D, wierzchołek)
usuwa z drzewa element wskazywany przez wierzchołek
(zachowując własność BST!)
przy pomocy drzewa BST. Oszacuj czas działania tych 3 operacji przyjmując jako
operację dominującą porównywanie wartości.