TEORIA GRAFÓW I SIECI - ROZDZIAŁV Przeszukiwanie grafów Wiedza o istnieniu interesujacego nas obiektu (np. drzewa spinajacego) jest w praktycznych zastosowaniach mało przydatna. Na ogółpotrzebujemy informacji o sposobie znalezienia tego obiektu, czyli potrzebujemy odpowiedniego algorytmu. Jednak algorytm, którego czas działania wynosi 1000 lat, jest umiarkowanie przydatny. Potrzebne sa więc metody pozwalajace stwierdzić, który ze znanych algorytmów jest szybszy, a przynajmniej takie które pozwalaja ocenić, czy algorytm jest wystarczajaco szybki dla naszych potrzeb. Interesuje nas zatem czas działania algorytmu. Jest on oczywiście zależny od rozmiaru danych wejściowych. Jednak nawet przy tym samym rozmiarze danych, czas pracy algorytmu może być znaczaco różny. Nas będzie interesować pesymistyczny czas działania, czyli najdłuższy możliwy czas działania dla danych wejściowych określonego rozmiaru. Będziemy przy tym zakładać, że wprowadzamy dane jednego typu, czyli rozmiar danych wejściowych można określić jedna liczba n (w ogólnym przypadku rozważania sa podobne). W praktyce nie będziemy wyznaczać dokładnego czasu T (n), a jedynie będziemy szukać dobrego oszacowania górnego. Obliczenie czasu działania algorytmu polega na zsumowaniu czasu działania wszystkich prostych (elementarnych) instrukcji, takich jak przypisanie wartości (i := i + 1), porównanie (if a > 0 then... ), czy wywołanie procedury. Algorytm zawiera pewna liczbę instrukcji prostych, przy czym niektóre z nich sa wykonywane wielokrotnie w pętli. Czasy poszczególnych instrukcji prostych, zwane też ich kosztami, oznaczmy przez c 1,..., c k. Zastępujac koszty poszczególnych instrukcji największym z nich c = max {c 1,..., c k } dostajemy oszacowanie czasu T (n) pewna funkcja f(n), której współczynniki zależa od c. Rozważmy przykładowo algorytm znajdowania maksimum n liczb. Dane wejściowe stanowi tablica a = [a[1],,..., a[n]]. Maksimum(a) % koszt krotność x := a[1] % c 1 1 for i := 2 to n do % c 2 n 1 if a[i] > x then % c 3 n 1 x := a[i] % c 1 n 1 max := x % c 4 1 Z powyższej (uproszczonej) analizy algorytmu wynika, że pesymistyczny czas jego działania można oszacować następujaco: T (n) = c 1 + (n 1) c 2 + (n 1) c 3 + (n 1) c 1 + c 3 c + (n 1) c + (n 1) c + (n 1) c + c = 3cn c, czyli czas działania jest ograniczony z góry przez funkcję f (n) = 3cn c. 1
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 2 Zauważmy, że problemy z czasem działania algorytmu moga się pojawić przy dużym rozmiarze danych wejściowych. Oznacza to, że interesujace sa dla nas nie tyle konkretne wartości ograniczajacej funkcji f (n), co zachowanie przy n, czyli jej własności asymptotyczne. Badanie własności asyptotycznych funkcji f będzie polegało na porównaniu jej z pewna funkcja g > 0, której własności sa nam znane. Pojawia się pytanie, jak porównać asymptotyczne własności funkcji f oraz g. Polega to, mówiac w uproszczeniu, na zbadaniu granicy A = lim n f (n) g (n). Jeżeli A jest liczba dodatnia, to uważamy, że funkcje te sa "asymptotycznie podobne", jeżeli A = 0, to f jest "asymptotycznie mniejsza", zaś jeśli A =, to f jest "asymptotycznie większa" niż g. Przyjmujac np. g (n) = n, w rozważanym przykładzie dostajemy f (n) lim n g (n) = 3c (0, ), czyli f i g sa "asymptotycznie podobne". Takie podejście pozwala na uproszczenie rozważań przez pominięcie w rozważaniach kosztu c, który nie wpływa na asymptotyczne własności funkcji. Dokładniej, przyjmujemy c = 1, co sprawia, że funkcja f (n) szacuje ilość instrukcji prostych w algorytmie, czyli złożoność obliczeniowa algorytmu. W ostatnim przykładzie mamy f (n) = 3cn c = 3n 1. Sprowadziliśmy rozważania dotyczace czasu działania algorytmu do badania jego (pesymistycznej, asymptotycznej) złożoności obliczeniowej. Zdefiniujemy teraz formalnie pojęcia pozwalajace opisać złożoność obliczeniowa algorytmu. Dla k N oznaczmy N k = {n N; n k} i załóżmy, że f, g : N k R +. Mówimy, że funkcja g (n) jest asymptotycznym ograniczeniem górnym funkcji f (n) lub że f (n) jest rzędu co najwyżej g (n) jeżeli lim sup n f (n) g (n) <. Zbiór takich funkcji f (n), dla których g (n) jest asymptotycznym ograniczeniem górnym oznaczamy O (g (n)). Zamiast pisać f (n) O (g (n)) będziemy, zgodnie z przyjętymi zwyczajami, pisać f (n) = O (g (n)). Przyjęte oznaczenia nazywamy notacja O (wielkie O). Ćwiczenie 1. Pokazać, że f (n) = O (g (n)) c>0 n0 N n n0 f (n) cg (n). Funkcja g (n) pełni w podanej definicji rolę wzorca, do którego porównujemy funkcję f (n). Dlatego jako g (n) będziemy przyjmować na ogółfunkcje: 1 (stała), ln n, n, 2 n oraz iloczyny tych funkcji. Przykładowo, funkcję f (n) nazywamy ograniczona wielomianowo jeśli f (n) = O ( n k) dla pewnej liczby naturalnej k. Ćwiczenie 2. Pokazać, że dla dowolnych funkcji f, g, h : N k R +
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 3 (1) f (n) = O (f (n)). (2) Jeżeli f (n) = O (g (n)) i g (n) = O (h (n)), to f (n) = O (h (n)). Ćwiczenie 3. Znale zć funkcje takie, że (1) f (n) = O (g (n)) oraz g (n) O (f (n)) (czyli g (n) / O (f (n))). (2) f (n) O (g (n)) oraz g (n) O (f (n)). (3) f (n) = O (g (n)), g (n) = O (f (n)) oraz f g. Ćwiczenie 4. W zbiorze funkcji z N k w R + możemy wprowadzíc relację przyjmujac Jakie własno sci ma relacja? f g f (n) = O (g (n)). Ćwiczenie 5. Udowodníc, że dla dowolnej liczby a > 0 ln a n lim n n = lim n a n 2 = 0. n Ćwiczenie 6. Sprawdzíc prawdziwo sć warunków 1) n = O (n 3 ) ; 10) ln 5 n = O ( n) ; 19) 2 n + 3 n = O (3 n ) ; 2) n 2 = O (n 3 ) ; 11) ln n 5 = O (ln n) ; 20) n2 n = O (3 n ) ; 3) n 3 = O (n 2 ) ; 12) ln 5 n = O (ln n) ; 21) 5 n = O (n!) ; 4) n 3 = O (5n 3 + 4n 2 + 3n + 2) ; 13) ln n = O (log 2 n) ; 22) n! = O (5 n ) ; 5) 5n 3 + 4n 2 + 3n + 2 = O (n 3 ) ; 14) ln n = O (log 10 n) ; 23) ln 2 n = O (n) ; 6) n + n = O (n) ; 15) ln n = O (ln ln n) ; 24) ln n! = O (n) ; 7) n n = O (n) ; 16) n 5 = O (2 n ) ; 25) ln n! = O (n ln n) ; 8) n = O (ln n) ; 17) 2 n = O (n 5 ) ; 26) ln n! = O (n 2 ) ; 9) ln n = O ( n) ; 18) 4 n = O (2 n + 3 n ) ; 27) n n = O (n!). Oprócz notacji O stosowane sa również inne sposoby porównywania funkcji. Wspomnimy o jeszcze jednym zwanym notacja Θ (wielkie theta). Mówimy, że funkcja g (n) jest asymptotycznie dokładnym oszacowaniem funkcji f (n) lub że f (n) jest rzędu g (n) jeżeli 0 < lim inf n Piszemy wtedy f (n) = Θ (g (n)). f (n) g (n) lim sup n f (n) g (n) <. Ćwiczenie 7. Udowodníc, że dla dowolnych funkcji f, g, h : N k R + (1) f (n) = Θ (g (n)) f (n) = O (g (n)) g (n) = O (f (n)). (2) f (n) = Θ (f (n)). (3) f (n) = Θ (g (n)) g (n) = Θ (f (n)). (4) Jeżeli f (n) = Θ (g (n)) i g (n) = Θ (h (n)), to f (n) = Θ (h (n)). Ćwiczenie 8. Sprawdzíc prawdziwo sć warunków z ćwiczenia 6, po zastapieniu notacji O notacja Θ.
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 4 Uwaga 1. Definicje dotyczace porównywania funkcji można bez żadnych zmian sformułować dla funkcji okre slonych na półprostej (a, ), a > 0 zamiast na zbiorze N k (jedynie dla większej czytelno sci warto zmienna n zastapíc przez x). Uwaga 2. Zapisujac złożono sć obliczeniowa algorytmu upraszcza się zapis przez opuszczenie symbolu mocy zbioru, tzn. pisze się np. O (V 2 ) i O (V ln V ) zamiast O ( V 2) i O ( V ln V ). Zanim przejdziemy do omawiania konkretnych algorytmów, zwróćmy jeszcze uwagę na istotny problem występujacy gdy próbujemy ocenić złożoność obliczeniow a algorytmu napisanego w pseudokodzie. Problem polega na tym, że czasem nie da się ustalić, czy dana instrukcję możemy potraktować jako elementarna, czy też do jej wykonania potrzeba większej ilości instrukcji elementarnych. Przykładowo instrukcja przypisania odwołuj aca się do elementu tablicy może być potraktowana jako elementarna, gdyż możemy się odwołać bezpośrednio do dowolnego elementu tablicy. Jeżeli jednak dane sa zorganizowane nie w postaci tablicy, ale listy, to odwołanie do elementu listy wymaga odwołania się do wszystkich go poprzedzajacych. Tak więc analogiczna instrukcja przypisania wymaga większej ilości instrukcji elementarnych. Przykład ten pokazuje, że na ogółzłożoność obliczeniowa możemy policzyć dla konkretnej implementacji algorytmu, a nie dla samego algorytmu. Z tego też względu w naszym wykładzie będziemy ograniczać się do podawania informacji o złożoności obliczeniowej jaka można uzyskać implementujac dany algorytm. Nie będziemy raczej badać tego samodzielnie. W twierdzeniu?? udowodniliśmy, że każdy graf spójny ma drzewo spinajace. Dowód nie podawałjednak sposobu znalezienia takiego drzewa. Omówimy teraz algorytm znajdujacy drzewo spinajace grafu spójnego. Warunki z twierdzenia?? sugeruja dwa sposoby rozwiazania tego problemu: Usuwamy kolejne krawędzie dbajac o zachowanie spójności, tak długo jak to możliwe. Startujemy od zbioru pustego i dodajemy kolejne krawędzie dbajac o zachowanie acykliczności, tak długo jak to możliwe. Okazuje się, że bardziej efektywny jest, na ogół, algorytm oparty na drugim pomyśle. Algorytm oparty na pierwszym może być szybszy dla grafu rzadkiego, tzn. takiego, w którym ilość krawędzi E G jest dużo mniejsza niż kwadrat liczby wierzchołków V G 2. Jednak dla grafów rzadkich algorytm oparty na drugim pomyśle jest wystarczajaco szybki i w konsekwencji można go stosować do dowolnych grafów spójnych. Załóżmy, że G = (E, V ) jest grafem spójnym oraz a dowolnie wybranym wierzchołkiem. Drzewo(G, a) V 0 := {a} E 0 := while V \ V 0 do Wybierz krawędź bc taka, że b V 0 i c V \ V 0 V 0 := V 0 {c} E 0 := E 0 {bc} T := (V 0, E 0 )
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 5 Graf G Drzewo spinajace T Drzewo spinajace T Twierdzenie 1. Wynikiem działania procedury Drzewo jest drzewo spinajace T grafu spójnego G. Jeżeli nie zaznaczymy inaczej, sfor- Dowód. Udowodnimy kolejno kilka prostych faktów. mułowania będa dotyczyć dowolnej iteracji. (1) Końce krawędzi z E 0 należa do V 0 (czyli (V 0, E 0 ) jest grafem). Dla E 0 = jest to oczywiste. Własność (1) jest niezmiennikiem pętli, bo koniec krawędzi dodawanej do E 0 jest dodawany do V 0. (2) Jeżeli V \ V 0, to wybór krawędzi bc jest możliwy. Wystarczy wziać dowolny wierzchołek z V \ V 0 i poł aczyć go ścieżka z a (spójność). Na podstawie własności?? ścieżka ta zawiera szukana krawędź. (3) Procedura zatrzyma się. Wynika to ze skończoności V. (4) Własność "(V 0, E 0 ) jest drzewem" jest niezmiennikiem pętli. Spójność (V 0, E 0 ) jest niezmiennikiem pętli, bo dodawany wierzchołek jest poł aczony krawędzi a z wierzchołkiem należacym do V 0. Ponieważ w każdej iteracji dodajemy tyle samo wierzchołków co krawędzi, więc niezmiennikiem pętli jest także warunek Teza wynika zatem z twierdzenia??. E 0 = V 0 1. (5) Po wyjściu z pętli, (V 0, E 0 ) jest drzewem spinajacym G. Przed wejściem do pętli graf (V 0, E 0 ) = ({a}, ) jest drzewem. Z (4) wnioskujemy więc, że po wyjściu (V 0, E 0 ) jest również drzewem. Ponieważ mamy wtedy V 0 = V, więc jest to drzewo spinajace.
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 6 Dla grafu niespójnego pocedura Drzewo nie działa, bo po wyczerpaniu wszystkich wierzchołków ze składowej G a nie jest możliwy wybór kolejnej krawędzi bc. Jeśli jednak w pętli while warunek zastapimy warunkiem V \ V 0 istnieje krawędź bc taka, że b V 0 i c V \ V 0, to dostaniemy algorytm znajdujacy drzewo spinajace składowej G a. Ćwiczenie 9. Napisać algorytm znajdujacy drzewo spinajace grafu spójnego metoda usuwania z grafu kolejnych krawędzi i udowodníc poprawno sć działania. Problem znajdowania drzewa spinajacego grafu jest jednym z wielu, gdzie mamy do czynienia z przeszukiwaniem grafu, czyli przechodzeniem przez wszystkie wierzchołki. Przyjrzyjmy się algorytmowi Drzewo. Wykonywany w pętli wybór krawędzi nie jest jednoznaczny. Można więc wyobrazić sobie różne sposoby wybierania kolejnej krawędzi. Szukanie krawędzi polega na sprawdzeniu, czy już wybrane wierzchołki można poł aczyć krawędzi a z jeszcze niewybranymi. Istotna jest zatem kolejno sć w jakiej przegladamy wierzchołki już wybrane. Zmieniajac kolejność dostaniemy różne algorytmy przeszukiwania grafu. Dwa najważniejsze to przeszukiwanie wszerz i przeszukiwanie w gł ab. Procedura przeszukiwania rozpoczyna się od wyróżnionego wierzchołka, który nazywamy korzeniem drzewa. Przeszukiwanie wszerz (BFS - breadth first search). Przeszukujac wszerz szukamy najpierw sasiadów korzenia. Wierzchołki te tworza pierwszy poziom. Następnie szukamy sasiadów wierzchołków pierwszego poziomu (wśród jeszcze niewybranych). Wierzchołki pierwszego poziomu przegł adamy w kolejności w jakiej były wybierane. Znalezione wierzchołki tworza drugi poziom. Operacje wyszukiwania powtarzamy na kolejnych poziomach, dopóki nie znajdziemy wszystkich wierzchołków. Poniższy przykład pokazuje drzewo przeszukiwania wszerz, czyli drzewo spinajace T B uzyskane z wykorzystaniem przeszukiwania wszerz. Korzeniem jest wierzchołek a, zaś sasi- adów wybieramy w kolejności alfabetycznej. Kolejność wybierania krawędzi jest oznaczona liczbami. Graf G Drzewo przeszukiwania wszerz T B
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 7 Przeszukiwanie w gł ab (DFS - depth first search). Zaczynamy przeszukiwanie od korzenia i szukamy sasiada ostatnio odwiedzonego wierzchołka. Jeżeli nie znajdziemy, to cofamy się do poprzednio odwiedzonego i szukamy sasiada dla niego. Używajac przeszukiwania w gł ab, znajdziemy drzewo spinajace T D grafu z poprzedniego przykładu. Jest ono nazywane drzewem przeszukiwania w gł ab. Tak jak poprzednio, sasiadów wybieramy w kolejności alfabetycznej i numerujemy krawędzie w kolejności znajdowania. Graf G Drzewo przeszukiwania w gł ab T D Ćwiczenie 10. Załóżmy, że graf G jest reprezentowany w postaci macierzy sasiedztwa. (1) Zmodyfikować (uszczegółowíc) algorytm Drzewo tak by wynikiem było drzewo przeszukiwania wszerz. (2) Zmodyfikować algorytm tak by wynikiem było drzewo przeszukiwania w gł ab. (3) Oszacować złożono sć obliczeniowa utworzonych algorytmów. Przeszukujac graf wyróżniliśmy jeden wierzchołek (poczatek przeszukiwania). W wyniku tego dostaliśmy drzewo majace pewna strukturę. Drzewem z wyróżnionym korzeniem (drzewem ukorzenionym) nazywamy parę (T, r), gdzie T jest drzewem, zaś r wyróżnionym wierzchołkiem, nazywanym korzeniem drzewa. Dowolny wierzchołek drzewa można poł aczyć z korzeniem dokładnie jedna ścieżka prosta. Długość tej ścieżki nazywamy numerem poziomu wierzchołka. Zbiór wszystkich wierzchołków o numerze poziomu równym n nazywamy n- tym poziomem drzewa. Największy numer poziomu wierzchołka nazywamy wysokości a drzewa. Jeżeli wierzchołek b leży na ścieżce prostej z korzenia do wierzchołka c b to mówimy, że c jest potomkiem b. Jeżeli b jest przedostatnim wierzchołkiem na tej ścieżce, to wierzchołek c nazywamy synem (dzieckiem, następnikiem) b, zaś wierzchołek b ojcem (rodzicem, poprzednikiem) c. Podgraf T b złożony z b, wszystkich jego potomków oraz krawędzi ł aczacych te wierzchołki jest drzewem. Parę (T b, b) nazywamy poddrzewem o korzeniu b. Liśćmi w drzewie ukorzenionym nazywamy wszystkie wierzchołki stopnia 1,
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 8 oprócz korzenia. Drzewo z wyróżnionym korzeniem przedstawiamy graficznie rysujac korzeń na górze, a dzieci niżej niż rodziców. Drzewo przeszukiwania w gł ab z ostatniego przykładu może być traktowane jako drzewo z wyróżnionym korzeniem a. Dla drzewa ukorzenionego (T D, a) mamy: ojciec g: c, synowie g: f, h, potomkowie g: f, e, i, j, h, l, k, 0. poziom drzewa: a, 3. poziom drzewa: d, g, wysokość drzewa: 6, liście: d, e, j, k, poddrzewo (T g, g):. Własność 1. Jeżeli (T, r) jest drzewem ukorzenionym, to (1) Korzeń r nie ma ojca. (2) Dowolny wierzchołek różny od korzenia ma dokładnie jednego ojca. Dowód. Jedyna ścieżka prosta z r do r jest ścieżka trywialna. Nie istnieje więc przedostatni wierzchołek na tej ścieżce, czyli r nie ma ojca. Niech b będzie wierzchołkiem różnym od korzenia. Istnieje dokładnie jedna ścieżka prosta z r do b. Ponieważ b r, więc jest ona nietrywialna. Ojciec b jest zatem wyznaczony jednoznacznie jako przedostatni wierzchołek na tej ścieżce. Własność 2. Jeżeli wierzchołki a, b drzewa ukorzenionego (T, r) sa poł aczone krawędzi a, to a jest ojcem b albo b jest ojcem a. Dowód. Ponieważ T jest grafem acyklicznym, więc a b. Zatem przynajmniej jeden z rozważanych wierzchołków jest różny od r. Możemy przyjać, że b r. Ze spójności T wynika, że istnieje ścieżka prosta d = r... b. Rozważmy przypadki. (1) a nie należy do d. Wtedy a nie jest ojcem b. Ponadto r... ba jest ścieżka prosta, czyli b jest ojcem a. (2) a jest przedostatnim wierzchołkiem w d, czyli d = r... ab. Wówczas a jest ojcem b. Ponieważ podścieżka r... a nie zawiera b, więc b nie jest ojcem a. (3) a należy do d, ale nie jest przedostatnim wierzchołkiem w d, czyli d = r... a... b. Dodajac do ścieżki prostej a... b (długości > 1) krawędź ba dostajemy cykl a... ba,
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 9 wbrew acykliczności T. Wynika stad, że ten przypadek nie może zachodzić. Z (1)-(3) wnioskujemy tezę. Ćwiczenie 11. Pokazać, że w nietrywialnym drzewie ukorzenionym líscie sa jedynymi wierzchołkami, które nie maja synów. Ćwiczenie 12. (1) W drzewie (T B, a) z przedostatniego przykładu powtórzyć obliczenia, które zrobilísmy dla drzewa (T D, a). (2) Traktuj ac T B i T D jako drzewa wolne, utworzyć (narysować) drzewa ukorzenione (T B, f) i (T D, f). Powtórzyć obliczenia wykonane dla (T D, a) i (T B, a). (3) Dla grafu G utworzyć drzewo przeszukiwania wszerz (T 1, f) i drzewo przeszukiwania w gł ab (T 2, f). Powtórzyć obliczenia wykonane dla (T D, a) i (T B, a). Ćwiczenie 13. W poniższym grafie (1) Znale zć drzewo spinajace T B przeszukujac graf wszerz oraz drzewo spinajace T D przeszukujac graf w gł ab. Przeszukiwanie rozpocz ać od wierzchołka a, wierzchołki wybierać w kolejno sci alfabetycznej. (2) Narysować drzewa ukorzenione (T B, a) i (T D, a). Wyznaczyć: líscie, trzeci poziom, wysoko sć drzewa, synów wierzchołka e, potomków wierzchołka d (narysować poddrzewo o korzeniu d). (3) Powtórzyć (1) i (2) zastępujac wierzchołek a wierzchołkiem h. Zauważmy, że przeszukujac graf omówionymi metodami (wszerz, w gł ab), mamy dowolność w wybieraniu sasiada danego wierzchołka (w przykładach i ćwiczeniach robiliśmy to alfabetycznie). Dokonujac wyboru wprowadzamy, de facto, pewien porzadek w zbiorze dzieci
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 10 poszczególnych wierzchołków, który graficznie oddajemy rysujac dziecko wybrane wcześniej na lewo od wybranego później. Oznacza to, że otrzymane w ten sposób drzewo ukorzenione ma dodatkowa strukturę. Zanim ja formalnie opiszemy zauważmy, że dla zbioru skończonego, ustawienie jego elementów w ciag skończony (ponumerowanie) jest równoznaczne ze zdefiniowanie w nim relacji liniowego porzadku. Drzewo z wyróżnionym korzeniem nazywamy uporzadkowanym, jeżeli dla dowolnego wierzchołka, zbiór jego dzieci jest liniowo uporzadkowany (o ile jest niepusty). Jak wcześniej wspomnieliśmy, drzewa spinajace otrzymane w wyniku działania algorytmu Drzewo można traktować jako uporzadkowane drzewa z wyróżnionym korzeniem. Porzadek w zbiorze dzieci danego wierzchołka jest określony przez kolejność wyboru. Przykładowo w rozpatrywanych wyżej drzewach przeszukiwania wszerz i przeszukiwania w gł ab byłto porzadek alfabetyczny. Zagadnienie przeszukiwania grafu jest zwiazne z problemem porzadkowania wierzchołków grafu, tj. ustawiania ich w ciag. Graf spójny i jego drzewo spinajace maja te same wierzchołki. Porzadkowanie wierzchołków grafu spójnego sprowadza się więc do porzadkowania wierzchołków jego drzewa spinajacego. Dwa podstawowe sposoby porzadkowania wierzchołków: prefiksowy (preorder) i postfiksowy (postorder) wykorzystuja drzewo przeszukiwania w gł ab. Opis procedury porzadkujacej wierzchołki drzewa można jednak sformułować dla dowolnego uporzadkowanego drzewa z wyróżnionym korzeniem. Załóżmy, że mamy uporzadkowane drzewo z wyróżnionym korzeniem (T, r). Ustawimy wierzchołki tego drzewa w ciag. W tym celu tworzymy zamknięta ścieżkę o poczatku r według następujacych reguł: Jeżeli bieżacy wierzchołek ma nieodwiedzone jeszcze dzieci, to idziemy (dodajemy krawędź) do pierwszego nieodwiedzonego dziecka (zgodnie z porzadkiem w zbiorze dzieci). Jeżeli bieżacy wierzchołek nie ma nieodwiedzonych dzieci, to cofamy się (dodajemy krawędź) do ostatnio odwiedzonego wierzchołka. Procedurę kończymy, jeśli po osiagnięciu korzenia okaże się, że wszystkie jego dzieci były już odwiedzone. Można sprawdzić, że w wyniku opisanej wyżej procedury powstaje ścieżka zamknięta zawierajaca wszystkie wierzchołki drzewa T. Niektóre wierzchołki występuja tam wielokrotnie. Naturalne sa dwa sposoby uporzadkowania wierzchołków (ustawienia w ciag). Porzadek prefiksowy (preorder) Wierzchołek wstawiamy do ciagu przy pierwszym pojawieniu się na ścieżce. Porzadek postfiksowy (postorder) Wierzchołek wstawiamy do ciagu przy ostatnim pojawieniu się na ścieżce.
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 11 Dla rozpatrywanego wcześniej drzewa przeszukiwania w gł ab mamy Porzadek preorder: a, b, c, d, g, f, e, i, j, h, l, k. Porzadek postorder: d, e, j, i, f, k, l, h, g, c, b, a. W uporzadkowaniu prefiksowym rodzice sa umieszczeni w ciagu przed dziećmi, a w postfiksowym - po dzieciach. Ćwiczenie 14. Traktuj ac drzewa ukorzenione z ćwiczeń 12 i 13 jako drzewa uporzadkowane (kolejno sć dzieci alfabetyczna), uporzadkować ich wierzchołki w porzadku prefiksowym i postfiksowym. Aby uzyskać algorytm porzadkowania wierzchołków grafu spójnego musimy poł aczyć algorytm tworzenia drzewa przeszukiwania w gł ab (algorytm Drzewo w wersji z ćwiczenia 10) z metoda opisana powyżej. Ćwiczenie 15. Napisać algorytmy porzadkowania wierzchołków grafu spójnego w porzadku preorder i w porzadku postorder (użyć pseudokodu lub jakiegokolwiek języka programowania). Drzewo ukorzenione, w którym każdy wierzchołek ma co najwyżej dwóch synów nazywamy drzewem binarnym. Jeżeli dla pewnej liczby naturalnej m, każdy wierzchołek ma co najwyżej m synów, to drzewo nazywamy m-arnym. Drzewa binarne odgrywaja szczególnie duża rolę w zastosowaniach. Uporzadkowane drzewa binarne sa definiowane w specyficzny sposób. Dla ustalonego wierzchołka a, zbiór jego dzieci ma 1 lub 2 elementy (o ile jest niepusty). Zamiast wprowadzać liniowy porzadek w tym zbiorze, jego elementom przypisujemy wartości 0 lub 1 (w sposób różnowartościowy). Dziecko, któremu przypisano wartość 0 nazywamy dzieckiem lewym, zaś wartość 1 - dzieckiem prawym. Oznacza to, że poniższe rysunki reprezentuja różne uporzadkowania drzewa binarnego o korzeniu r.
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 12 Dla drzew binarnych można wprowadzić jeszcze jedna metodę porzadkowania wierzchołków. Porzadek infiksowy (inorder). Wierzchołek wstawiamy do ciagu między lewym a prawym dzieckiem. Dla grafów z ostatniego rysunku mamy: lewy graf: c, a, d, r, e, b, prawy graf: c, a, d, r, b, e. Wróćmy do definicji drzewa z wyróżnionym korzeniem. Zauważmy, że traktujac ojca jako poczatek, a syna jako koniec krawędzi, przekształcamy drzewo ukorzenione (T, r) w graf skierowany T. Dokładniej definiujemy T przyjmujac V T = V T oraz E T = {(a, b) ; a, b V T a jest ojcem b}. Otrzymany w ten sposób graf skierowany nazywamy drzewem skierowanym z wyróżnionym korzeniem. (T, r) T Wierzchołek a grafu skierowanego nazywamy źródłem tego grafu jeśli indeg (a) = 0, natomiast ujściem jeśli outdeg (a) = 0. Z własności 1 wynika natychmiast, że w drzewie ukorzenionionym skierowanym T, korzeń jest jedynym źródłem. W dalszej części wykładu przyda się kryterium pozwalajace rozstrzygnać czy graf skierowany jest drzewem ukorzenionym. Twierdzenie 2. Graf skierowany G jest drzewem skierowanym z korzeniem r wtedy i tylko wtedy, gdy jego szkielet G N jest spójny oraz (1) indeg (r) = 0 i indeg (a) = 1 dla a r. Dowód. Załóżmy, że graf skierowany G jest drzewem skierowanym generowanym przez drzewo ukorzenione (T, r). Z definicji drzewa skierowanego oraz szkieletu wynika, że V T = V G = V GN. Z własności 2 wnioskujemy, że jeśli (a, b) E G, to (b, a) / E G i w konsekwencji szkielet G N nie ma krawędzi wielokrotnych. Korzystajac ponownie z własności 2, dla dowolnych wierzchołków a, b mamy {a, b} E GN (a, b) E G (b, a) E G b jest ojcem a w T a jest ojcem b w T {a, b} E T.
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 13 Oznacza to, że G N = T, czyli graf G N jest spójny. Warunek (1) wynika z własności 1, bo { 0 ; a = r indeg (a) = {x; (x, a) E G } = {x; x jest ojcem a w T } = 1 ; a r. Załóżmy, że G jest grafem skierowanym o spójnym szkielecie spełniaj acym (1). Lematu o uściskach dłoni dla grafów skierowanych mamy E GN = E G = a V G indeg a = a r 1 = V G 1 = V GN 1. Wobec spójności G N, z twierdzenia?? wynika, że G N jest drzewem. Aby zakończyć dowód wystarczy pokazać, że drzewo ukorzenione (G N, r) generuje graf skierowany G, tzn. (2) (a, b) E G a jest ojcem b w (G N, r). Udowodnimy najpierw, że (3) jeżeli a jest ojcem b w (G N, r), to (a, b) E G. Przypuśćmy nie wprost, że tak nie jest, tzn. istnieja wierzchołki a, b takie, że a jest ojcem b oraz (a, b) / E G. Wśród wszystkich par wierzchołków o tej własności wybierzmy a 0, b 0, dla których a 0 leży na poziomie o najmniejszym możliwym numerze k. Z założenia dostajemy (a 0, b 0 ) / E G, {a 0, b 0 } E GN i w konsekwencji (b 0, a 0 ) E G. Z Rozpatrzmy przypadki k = 0, tzn. a 0 = r. Wtedy (b 0, r) E G, co jest sprzeczne z założeniem indeg (r) = 0. k > 0. Wtedy a 0 ma na poziomie k 1 ojca c. Z minimalności k wynika, że (c, a 0 ) E G.
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 14 Ponieważ a 0 jest ojcem b 0, więc b 0 leży na poziomie k+1, czyli c b 0. Stad indeg a 0 2 > 1, co jest sprzeczne z założeniem. Otrzymane sprzeczności dowodza implikacji (3). Udowodnimy teraz implikację przeciwna: (4) jeżeli (a, b) E G, to a jest ojcem b w (G N, r). Załóżmy, że (a, b) E G i przypuśćmy nie wprost, że a nie jest ojcem b. Ponieważ {a, b} E GN, więc na podstawie własności 2, b jest ojcem a. Zatem z (3) wynika, że (b, a) E G i w konsekwencji wierzchołki a i b sa w grafie nieskierowanym G N poł aczone dwiema krawędziami. Jest to sprzeczne z acyklicznościa G N. Otrzymana sprzeczność dowodzi (4). Z (3) i (4) wynika (2), co kończy dowód twierdzenia. Niech (T, r) będzie drzewem z wyróżnionym korzeniem. Z własności 1 wynika, że r nie ma poprzednika (ojca), natomiast wszystkie wierzchołki a r maja dokładnie jednego poprzednika (ojca). Możemy więc na V T zdefiniować funkcję przyjmujac: { poprzednik a gdy a r, p (a) = gdy a = r. Funkcję p nazywamy wektorem poprzedników drzewa ukorzenionego (T, r) i często zapisujemy w postaci [p (a)] a VT. Jeśli wierzchołki drzewa T ustawimy w ciag V T = {x 1, x 2,..., x n }, to funkcja p jest wyznaczona przez wektor [p (x 1 ), p (x 2 ),..., p (x n )] i możemy ja z tym wektorem utożsamiać. Jeżeli (T, r) jest drzewem ukorzenionym, to w T możemy wprowadzić strukurę grafu skierowanego. Definicję wektora poprzedników stosuje się również w tym przypadku, tzn. dla skierowanych drzew z wyróżnionym korzeniem. Sytuacja taka jest nawet łatwiejsza do opisania bo mamy wtedy p (b) = a (a, b) E T. Zauważmy jeszcze, że przy ustalonym zbiorze wierzchołków V, wektor poprzedników p drzewa (skierowanego) T z korzeniem r jednoznacznie określa to drzewo. Korzeń r jest bowiem jedynym elementem zbioru {a V ; p (a) = } oraz E T = {(a, b) ; (a, b) E T } = {(a, b) ; p (b) = a V } = {(p (b), b) ; p (b) }, czyli zbiór krawędzi E T można wyznaczyć znajac funkcję p. Oczywiście, podobna zależność zachodzi też dla drzew ukorzenionych nieskierowanych. Wektor poprzedników stanowi zatem reprezentację analityczna drzewa ukorzenionego. Reprezentacja ta jest wygodniejsza niż rozważane wcześniej macierze sasiedztwa i incydencji, listy sasiedztw, czy kody Prüfera. Co więcej, również drzewo wolne można zapisać za pomoca wektora poprzedników. W tym celu wystarczy wyróżnić jakikolwiek wierzchołek jako korzeń.
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 15 Ćwiczenie 16. Znale zć wektor poprzedników dla następujacych drzew ukorzenionych (kolejno sć wierzchołków alfabetyczna) 1) 2) 3) 4) 5) Ćwiczenie 17. Wyznaczczyć drzewo ukorzenione (T, r) o zbiorze wierzchołków V = {1,..., n} oraz wektorze poprzedników p. (1) p = [4, 4, 6, 6,, 5]. (2) p = [, 1, 1, 1, 2, 2, 4, 4, 7, 9]. (3) p = [, 1, 2, 3, 3, 3, 1, 7, 7, 9, 9, 1]. (4) p = [7, 9, 7, 11, 10, 10,, 1, 1, 7, 10, 9]. (5) p = [2, 3, 13, 6, 6, 12, 10, 10, 10, 11, 12, 13, 14, ]. Ćwiczenie 18. Znale zć wektory poprzedników drzew z ćwiczenia?? przyjmujac r = 2 oraz r = 5 (kolejno sć wierzchołków rosnaca). Niech a będzie ustalonym wierzchołkiem drzewa ukorzenionego (T, r) (nieskierowanego). W T istnieje dokładnie jedna ścieżka prosta z a do r. Znajac wektor poprzedników p, możemy łatwo tę ścieżkę wyznaczyć. Ma on postać: a p (a) p (p (a))... Można to zapisać przy pomocy następujacego algorytmu. Path(p, a) x := a d := a while p (x) do d := d {x, p (x)} p (x) x := p (x) % bieżacy wierzchołek % zbudowana ścieżka
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 16 Wynikiem działania procedury Path jest ścieżka prosta d z wierzchołka a do korzenia r. Procedurę można też wykorzystać do szukania ścieżki prostej z korzenia do wierzchołka a (również dla drzew skierowanych). Należy jedynie zapisać wierzchołki ścieżki d w odwrotnej kolejności. Ćwiczenie 19. Znale zć scieżkę prosta z wierzchołka a do korzenia dla drzew, których wektor poprzedników jest równy p. Zakładamy, że V = {1,..., n}. (1) p = [, 1, 1, 1, 2, 2, 4, 4, 7, 9], a = 5. (2) p = [, 1, 1, 1, 2, 2, 4, 4, 7, 9], a = 10. (3) p = [, 1, 2, 3, 3, 3, 1, 7, 7, 9, 9, 1], a = 5. (4) p = [, 1, 2, 3, 3, 3, 1, 7, 7, 9, 9, 1], a = 10. (5) p = [2, 3, 13, 6, 6, 12, 10, 10, 10, 11, 12, 13, 14, ], a = 5. (6) p = [2, 3, 13, 6, 6, 12, 10, 10, 10, 11, 12, 13, 14, ], a = 10. Pojęcie wektora poprzedników można rozszerzyć na dowolne proste grafy skierowane. Załóżmy, że G = (V, E) jest prostym grafem skierowanym oraz r ustalonym wierzchołkiem. Funkcję p = [p (a)] a V taka, że p (r) = oraz dla a V \ {r} zachodzi (p (a), a) E lub p (a) = nazywamy wektorem poprzedników w G. Oznaczmy V p = {a; p (a) } {r} oraz E p = {(p (a), a) ; p (a) }. Para (V p, E p ) może, ale nie musi być podgrafem grafu G. Jeśli G p = (V p, E p ) jest podgrafem, to nazywamy go podgrafem poprzedników. Rozważmy graf skierowany G Dla r = 1 funkcje p 1 = [, 1, 2, 1, 4], p 2 = [, 1, 4, 2, ], p 3 = [, 4, 2, 2, ] sa wektorami poprzedników. Odpowiadaja im grafy poprzedników, z których dwa pierwsze sa drzewami skierowanymi o korzeniu 1, zaś trzeci jest grafem skierowanym, ale nie jest drzewem skierowanym.
TEORIA GRAFÓW I SIECI - ROZDZIAŁV 17 Podobnie dla r = 2 funkcja p = [,, 2, 2, ] jest wektorem poprzedników, dla którego graf poprzedników jest drzewem skierowanym o korzeniu 2. Przyjmuj ac natomiast r = 1 oraz p = [,, 2, 2, ] dostajemy wektor poprzedników taki, że V p = {1, 3, 4}, E p = {(2, 3), (2, 4)}. Para (V p, E p ) nie jest więc grafem, bo 2 / V p.