Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Algorytmy i Struktury Danych Wykład 5 Grafy. Przechodzenie grafu wszerz, w głąb. Minimalne drzewo rozpinające: algorytm Kruskala i algorytm Prima.

Podobne prezentacje


Prezentacja na temat: "Algorytmy i Struktury Danych Wykład 5 Grafy. Przechodzenie grafu wszerz, w głąb. Minimalne drzewo rozpinające: algorytm Kruskala i algorytm Prima."— Zapis prezentacji:

1 Algorytmy i Struktury Danych Wykład 5 Grafy. Przechodzenie grafu wszerz, w głąb. Minimalne drzewo rozpinające: algorytm Kruskala i algorytm Prima.

2 Podstawowe definicje Grafem to struktura oznaczona jako G=(V,E) składająca się ze skończonego i niepustego zbioru wierzchołków V i zbioru krawędzi E. Krawędź od wierzchołków u do v oznaczamy jako (v i,v j ). Drogą od wierzchołka v 1 do v n nazywamy sekwencję krawędzi: (v 1,v 2 ), (v 2,v 3 ),…, (v n-1,v n ) Dwa wierzchołki v i i v j nazywamy sąsiędnimi, jeżeli w zbiorze D istnieje krawędź (v i,v j ). Taką krawędź nazywamy incydentną do wierzchołków v i, v j. Stopniem wierzchołka v deg(v) – nazywamy liczbę krawędzi do niego incydentnych. Jeśli deg(v)=0 to jest to wierzchołek izolowany. Graf rzadki = to graf, dla którego |E| jest dużo mniejsze od |V| 2. Graf gęsty – to graf, dla którego |E| jest bliskie |V| 2.

3 Oznaczenia dla złożoności Czas działania dla grafu G=(V,E) najczęściej się mierzy w zależności od liczby wierzchołków |V| i liczby krawędzi |E|. Przyjmijmy, że zapis O(|V||E|) będziemy oznaczać jako O(V E).

4 Rodzaje grafów: Grafy proste graf pełny – każdy wierzchołek jest połączony krawędzią z każdym wierzchołkiem

5 Rodzaje grafów: Grafy złożone Multigraf – dwa wierzchołki mogą być połączone kilkoma krawędziami Pseudograf – pojawiają się pętle czyli krawędzie wychodzące z i wchodzące do tego samego wierzchołka

6 Rodzaje grafów: Grafy złożone Graf skierowany – krawędzie, zwane też łukami, spełniają warunek (u,v)≠(v,u) Graf ważony – gdy krawędziom zostają przyporządkowane liczby – wagi

7 REPREZENTACJA GRAFÓW:

8 Lista sąsiedztwa

9 Lista sąsiedztwa Niech będzie dany graf G=(V,E). Jego reprezentacja w postaci listy sąsiedztwa będzie zapisana w tablicy Adj zawierającej |V| list, gdzie każda lista odpowiadać będzie. odpowiedniemu wierzchołkowi z V. Dla każdego u  V elementami listy sąsiedztwa Adj[u] są wszystkie wierzchołki v takie że krawędź (u,v) należy do zbioru E. To oznacza, że Adj[u] zawiera wszystkie wierzchołki (lub wskaźniki do nich) sąsiadujące z u w grafie G. Formę listową preferuję się dla grafów rzadkich. Formę macierzową dla gęstych lub w przypadku Jeżeli graf G będzie miał skierowane krawędzie, to suma długości wszystkich list będzie wynosić |E|, związane jest to z tym, że krawędź postaci (u,v) to wystąpienie v na liście Adj[u]. Jeżeli zaś graf G będzie miał nieskierowane krawędzie to suma długości wszystkich list wierzchołków sąsiednich będzie dana wzorem 2|E|, gdyż dla nieskierowanej krawędzi (u,v), u znajdzie się na liście sąsiadów v a v na liście sąsiadów wierzchołka u. Rozmiar wymaganej pamięci przez reprezentację listową, niezależnie czy graf jest skierowany czy nie, wynosi  (V+E). Listę sąsiedztwa można wykorzystać do reprezentacji grafów ważonych. Wówczas posługujemy się funkcją wagową w:E  R. Dla danego grafu ważonego G=(V,E) funkcję wagową dla krawędzi (u,v) zapiszemy jako w(u,v). W praktyce oznacza to, że wagę pamiętamy obok wierzchołka sąsiedniego.

10 Macierz sąsiedztwa

11 Macierz sąsiedztwa

12 Macierz incydencji (1,2) (1,3) (1,4)(3,4)

13 Macierz incydencji

14 Algorytm przechodzenia grafu Niech G(V,E), n- liczba elementów zbioru V, m – liczba elementow zbioru m, p  V. Wybieramy wierzchołek startowy p  V, odwiedzamy go i zaznaczamy jako odwiedzony. Odkładamy wierzchołek w wybranej strukturze danych (stos – przechodzenie w głąb, kolejka –przechodzenie wszerz). Wykonujemy dopóki struktura danych wybrana do przechowywania wierzchołków nie jest pusta  odczytujemy numer wierzchołka ze struktury,  Jeśli odczytany wierzchołek ma sąsiada to:  odwiedzamy najbliższego jego „sąsiada” i zaznaczamy go jako odwiedzony,  jeśli „sąsiad” ma wierzchołki do odwiedzenia to odkładamy go do wybranej struktury,  jeśli odczytany wierzchołek nie ma sąsiada to usuwamy go ze struktury.

15 Przechodzenie grafu w głąb Inna nazwa dfs z ang. Depth First SearchDepth First Search Założenia: Graf jest reprezentowany w postaci listy sąsiedztwa lstw, gdzie lstw[i][0] – liczba sąsiadów dla i-tego wierzchołka, lstw[i][k] – gdzie k=1,2,…,maxs przyjmują wartości kolejnych wierzchołków „sąsiadów”, visited[|V|] – tablica przechowująca informacje, czy wierzchołek był odwiedzony – 1 czy nie -0, current[|V|] – tablica przechowująca wskaźniki do najbliższego sąsiada danego wierzchołka. Wierzchołki grafu są przechowywane na stosie,

16 DFS void dfs(int n){ int startowy=1; short int visited[maxw]; int current[maxw]; int v,p,w; for (v=1;v<=n;v++) { visited[v]=0; current[v]=startowy; } p=startowy; wizyta(p); // odwiedzamy wierzchołek p visited[p]=1;// zaznaczmy p jako odwiedzony if ((current[p]) <= (lstw[p][0])) { stos[0]=0; push(stos,p); while (stos[0] > 0) { v=front(stos); w=lstw[v][current[v]]; current[v]++; if (current[v]>lstw[v][0])pop(stos); if (visited[w]!=1){ wizyta(w); visited[w]=1; if ((current[w]) <= (lstw[w][0])) push(stos,w); } }} }

17 Przechodzenie wszerz Inna nazwa bfs - Breadth-first search Założenia: Graf jest reprezentowany w postaci listy sąsiedztwa lstw, gdzie lstw[i][0] – liczba sąsiadów dla i-tego wierzchołka, lstw[i][k] – gdzie k=1,2,…,maxs przyjmują wartości kolejnych wierzchołków „sąsiadów”, visited[|V|] – tablica przechowująca informacje, czy wierzchołek był odwiedzony – 1 czy nie -0, current[|V|] – tablica przechowująca wskaźniki do najbliższego sąsiada danego wierzchołka. Wierzchołki grafu są przechowywane w kolejce,

18 BFS void dfs(int n){ int startowy=1; short int visited[maxw]; int current[maxw]; int v,p,w; for (v=1;v<=n;v++) { visited[v]=0; current[v]=startowy; } p=startowy; wizyta(p); // odwiedzamy wierzchołek p visited[p]=1;// zaznaczmy p jako odwiedzony if ((current[p]) <= (lstw[p][0])) { enqueue(p); while (kolejka jest nie pusta) { v=front(kolejka); w=lstw[v][current[v]]; current[v]++; if (current[v]>lstw[v][0])dequeue(); if (visited[w]!=1){ wizyta(w); visited[w]=1; if ((current[w]) <= (lstw[w][0])) enqueue(w); } }} }

19 Przechodzenie w głąb-Przykład

20

21

22 Przechodzenie wszerz - przykład

23

24

25 Minimalne drzewa ropinające MST- minimum spanning tree

26 Rozrastanie się minimalnego drzewa rozpinającego Załóżmy, że mamy spójny graf nieskierowany G=(V,E) z funkcją wagową w:E  R. Aby znaleźć minimalne drzewo rozpinające możemy użyć algorytmu zachłannego polegającego na dołączaniu pojedynczych krawędzi w poszczególnych krokach. Oznaczmy przez Z – zbiór krawędzi. Na początku każdej iteracji zbiór Z stanowi podzbiór pewnego minimalnego drzewa rozpinającego. Jest to niezmiennik pętli. W każdym kroku szukamy krawędzi (u,v) którą możemy dodać do Z tak aby Z  {(u,v)} był podzbiorem minimalnego drzewa rozpinającego. Jest to krawędź bezpieczna dla Z, gdyż można ją dodać bezpiecznie do Z bez naruszenia niezmiennika.

27 MST - algorytm generyczny void generic_mst(graf G, waga w) { Z=  while Z nie tworzy minimalnego drzewa rozpinającego znajdź krawędź (u,v), będącą bezpieczną dla Z Z=Z  {(u,v)} return Z }

28 Podstawowe definicje Przekrój (S,V-S) grafu nieskierowanego G=(V,E) nazywamy podział V na zbiory S i V-S. Jeżeli jeden z krańców krawędzi (u,v)  E należy do S, a drugi do V-S to mówimy wówczas, że krawędź ta krzyżuje się z przekrojem (S,V-S). Przekrój uwzględnia zbiór krawędzi Z, jeżeli żadna z krawędzi z Z nie krzyżuje się z tym przekrojem.

29 Podstawowe definicje Jeżeli krawędź krzyżuje się z przekrojem to nazywa się ją krawędzią lekką, pod warunkiem że jej waga jest najmniejsza spośród wszystkich wag krawędzi krzyżujących się z tym przekrojem. Uogólniając, krawędź będziemy nazywać krawędzią lekką o danej własności, jeżeli jej waga będzie najmniejsza spośród wag wszystkich krawędzi o danej własności.

30 Twierdzenie Niech będzie dany spójny graf nieskierowany G=(V,E) z funkcją wagową w:E  R, Z określone jako podzbiór E zawarty w pewny minimalnym drzewie rozpinającym grafu G oraz niech (S, V-S) będzie dowolnym przekrojem G uwzględniającym Z i niech (u,v) będzie krawędzią lekką krzyżującą się z (S,V-S). Wówczas krawędź (u,v) jest bezpieczna dla Z. Wniosek Niech G=(V,E) będzie spójnym grafem nieskierowanym z funkcją wagową w o wartościach rzeczywistych, określoną na E. Niech Z będzie podzbiorem E zawartym w pewnym minimalnym drzewie rozpinającym grafu G i niech D=(V D,E D ) będzie spójną składową (drzewem) w lesie G z =(V,Z). jeśli (u,v) jest krawędzią lekką łączącą D z pewną inną składową w G z, to krawędź (u,v) jest bezpieczna dla Z.

31 Algorytm Kruskala void mst_kruskal(graf G, wagi w) { A=  for każdy wierzchołek v  G.V MAKE_SET(v) posortuj krawędzie z G.E rosnąco względem wag w for każda krawędź (u,v)  G.E, w kolejności rosnących wag {if FIND_SET(u)  FIND_SET(v) Z=Z  {(u,v)} UNION(u,v) } return Z }

32 Znaczenie operacji z pseudokodu MAKE_SET(x) – tworzy nowy zbiór, którego jedynym elementem jest x i x nie może być elementem innego zbioru (warunek rozłączności zbiorów), UNION(y, z) łączy dwa zbiory dynamiczne zawierające odpowiednio y i z w nowy zbiór będący ich sumą. Zakładamy, że przed wykonaniem operacji te dwa zbiory były rozłączne. FIND_SET(x) – zwraca wskaźnik do reprezentanta (jedynego) zbioru zawierającego x.

33 Algorytm Kruskala - przykład

34

35

36

37 Algorytm Prima. Krawędzie ze zbioru Z tworzą tu zawsze pojedyncze drzewo. Najpierw drzewo zawiera dowolnie wybrany wierzchołek-korzeń r. Następnie w każdym kroku dodaje się do niego krawędź lekką łączącą wierzchołek z drzewa Z z izolowanym wierzchołkiem G z =(V,Z). Wszystkie wierzchołki znajdujące się poza drzewem, ustawione są w kolejce priorytetowej Q typu min. Dla każdego wierzchołka v kluczem v.key, który ustala pozycję w kolejce, jest minimalna waga spośród wag krawędzi łączących v z wierzchołkami drzewa. Jeśli krawędzi nie ma to przyjmujemy, że v.key=∞. Natomiast atrybut v.  oznacza ojca wierzchołka v w obliczanym drzewie. Podczas wykonywania algorytmu zbiór Z z procedury generic_mst jest pamiętany niejawnie jako Z={(v,v.  ):v  V-{r}-Q} Kiedy algorytm kończy zadanie, kolejka priorytetowa Q jest pusta a minimalnym drzewem rozpinającym Z w grafie G jest: Z={(v,v.  ):v  V-{r}}.

38 Algorytm Prima - pseudokod void mst_prim(graf G, wagi w, korzeń r) { for każdy u  G.V { u.key=∞ u.  =NIL } r.key=0 Q=G.V while Q  { u=EXTRACT-MIN(Q) for każdy v  G.adj[u] if v  Q I w(u,v)

39 Algorytm Prima - przykład

40

41

42

43

44 Bibliografia A. Drozdek, „C++. Algorytmy i struktury danych”, Helion, Gliwice 2004; L. Banachowski, K. Diks, W. Rytter, „Algorytmy i struktury danych”, WNT, Warszawa1996; Cormen Thomas; Leiserson Charles; Rivest Ronald; Stein Clifford, „Wprowadzenie do Algorytmów”, Wydawnictwo Naukowe PWN, Warszawa 2012.


Pobierz ppt "Algorytmy i Struktury Danych Wykład 5 Grafy. Przechodzenie grafu wszerz, w głąb. Minimalne drzewo rozpinające: algorytm Kruskala i algorytm Prima."

Podobne prezentacje


Reklamy Google