Fastbar
Powrót do strony głównej
Trzymaj pliki na gmclan.org!
Game Maker w pytaniach i odpowiedziach!
Polska dokumentacja
Tabela wyników ligi 24
Pobierz GM
Kategorie bazy artykułów
Artykuły -> Kąciki programowania -> Algorytmy i struktury danych
Treść artykułu
Wprowadzenie do teorii grafów - cz. 2
autor: Platyna (24.05.09)
Wstęp do teorii grafów - cz. 2

Sposoby reprezentacji grafów
     Człowiekowi najłatwiej wyobrazić sobie graf jako rysunek na którym punktami oznaczamy wierzchołki, a odcinkami (lub strzałkami) krawędzie grafu. W przypadku komputera jest trochę trudniej. Nie zrozumie, jeśli mu pokażemy nasze bazgroły. ;) W tej części artykułu omówione zostaną dwa najczęściej spotykane sposoby reprezentacji grafów w programowaniu. Przedstawione zostaną ich wady, zalety, możliwości jakie nam dają a także różne sposoby implementacji.
     UWAGA W zrozumieniu poniższych treści przydatne może okazać się zaznajomienie z podstawowymi strukturami danych (listy, kolejki, stosy itp.).
Miłej lektury :)

Macierz sąsiedztwa
     Jest to chyba najbardziej intuicyjny sposób przetrzymywania grafu. Polega on na utworzeniu macierzy o liczbie kolumn i wierszy równej liczbie wierzchołków grafu. Macierz jest czymś w rodzaju prostokątnej tabeli danych o określonej liczbie wierszy i kolumn. W komórce na pozycji (i,j) (gdzie i to numer wiersza, a j numer kolumny) będziemy przechowywali wartość 1 jeżeli istnieje krawędź prowadząca od wierzchołka i do wierzchołka j lub wartość 0 jeżeli taka krawędź nie istnieje. W przypadku grafów ważonych z krawędziami o określonych wagach zamiast 1 będziemy przechowywali wagę krawędzi. Myślę, że najlepiej będzie jeśli pokażę jakiś przykład. Rysunek 2 przedstawia spójny graf skierowany oraz odpowiadającą mu macierz sąsiedztwa.

     Może teraz coś o wadach i zaletach takiej reprezentacji grafów. Największą wadą takiego rozwiązania jest jego złożoność pamięciowa. Gdy byśmy chcieli w taki sposób przechowywać graf o bardzo dużej ilości wierzchołków, np. 100.000 musieli byśmy utworzyć macierz posiadającą 10.000.000.000 komórek, a tego nie wytrzymał by żaden komputer. No, a jakie korzyści nam daje macierz sąsiedztwa? Przede wszystkim możemy w prosty sposób, w czasie stałym sprawdzić czy dane dwa wierzchołki są połączone krawędzią. W tym celu wystarczy sprawdzić zawartość jednej komórki macierzy. W równie prosty sposób możemy usunąć lub dodać nową krawędź do grafu zmieniając w tym celu jedną wartość. Niestety gorzej ma się sprawa z wyszukaniem wszystkich sąsiadów danego wierzchołka. Aby odnaleźć wszystkie wierzchołki połączone z wierzchołkiem i musimy przeszukać cały wiersz i macierzy w poszukiwaniu jedynek.
     Taka reprezentacja grafu ma jeszcze jedną wadę. Rozważmy sytuację w której od pewnego wierzchołka i do wierzchołka j prowadzi więcej niż jedna krawędź. W takim wypadku w odpowiedniej komórce zamiast wartości 1 mogli byśmy przechowywać liczbę krawędzi łączących wierzchołki i i j. Gorzej sytuacja się ma jeśli wszystkim takim krawędziom przypisane są różne wagi. Na szczęście z takimi grafami nie mamy często do czynienia.

Implementacja
     Tutaj nie ma specjalnie o czym opowiadać. Znam tylko jeden sposób implementacji macierzy sąsiedztwa i jest on bardzo prosty. Polega na utworzeniu dwuwymiarowej tablicy o obu wymiarach równych liczbie wierzchołków. Tablica ta będzie odpowiadała naszej macierzy.

Listy sąsiedztwa
     Drugą często spotykaną reprezentacją grafu są tzw. listy sąsiedztwa. Polega ona na tym, że dla każdego wierzchołka tworzymy listę jego sąsiadów (czyli wierzchołków połączonych z nim pojedynczą krawędzią). Zwykle złożoność pamięciowa takiego rozwiązania jest znacznie lepsza niż w przypadku macierzy. Dla każdego wierzchołka tworzymy tyle zmiennych ile ma on sąsiadów, a więc tyle ile istnieje krawędzi odchodzących od niego. Tak więc całkowita złożoność pamięciowa tej reprezentacji jest proporcjonalna do liczby krawędzi grafu. No, ale niestety zdarzają się przypadki w których rozwiązanie to będzie równie pamięciożerne co macierz sąsiedztwa . Rozważmy taką reprezentację dla grafu pełnego skierowanego. Będzie miał on (n*(n-1)) krawędzi, a więc będzie wymagał od nas utworzenia właśnie tylu zmiennych. Na szczęście w praktyce rzadko mamy do czynienia z takimi grafami. Rysunek 3 przestawia przykładowy niespójny graf oraz odpowiadające mu listy sąsiedztwa.

     A na co nam pozwala takie rozwiązanie? Przede wszystkim możemy w prosty sposób uzyskać informacje o wszystkich sąsiadach danego wierzchołka. Jest to bardzo użyteczne przy implementowaniu wielu algorytmów grafowych. Przy odpowiedniej implementacji również dodanie krawędzi jest niezwykle proste, gdyż sprowadza się jedynie do dodania nowego wierzchołka do odpowiedniej listy. Niestety coś za coś. Gorzej sprawa się ma jeśli chcemy sprawdzić czy istnieje krawędź prowadząca od wierzchołka i do j. W tym celu musimy przeszukać całą listę sąsiadów wierzchołka i by sprawdzić czy występuje na niej wierzchołek j. Podobnie wygląda usuwanie krawędzi. Należy odnaleźć odpowiedni wierzchołek na liście i go stamtąd usunąć.

Implementacja
     Wymienione wcześniej wady i zalety list sąsiedztwa są w dużym stopniu zależne od sposobu implementacji i zastosowanej struktury danych. Postaram się przybliżyć wam dwa najpopularniejsze sposoby.

Sposób 1 - Tablica wskaźników
     Jest to zdecydowanie najgorsza metoda, jednak należy się z nią zapoznać. Polega na utworzeniu pewnej tablicy (lub vectora) o rozmiarze równym ilości wszystkich krawędzi. Nazwijmy ją A. W kolejnych pierwszych komórkach przechowywać będziemy sąsiadów wierzchołka numer 1. Następne komórki będą przechowywać sąsiadów wierzchołka 2, itd. Uzyskamy w ten sposób listę sąsiadów wszystkich wierzchołków. Jednak skąd będziemy wiedzieć w którym miejscu kończą się sąsiedzi jedynki, a zaczynają się sąsiedzi dwójki? Jest na to prosty sposób. Należy utworzyć drugą tablicę (nazwijmy ją W), która dla każdego wierzchołka będzie przechowywała informację o tym, w którym miejscu tablicy A zaczynają się jego sąsiedzi. Kończyć oczywiście będą się w miejscu wskazywanym przez następną komórkę tablicy W. Rysunek 4 przedstawia przykładowy graf oraz odpowiadające mu zawartości tablic A i W. Podstawową wadą takiego rozwiązania jest fakt, że gdybyśmy chcieli usunąć jakąś krawędź musieli byśmy przesunąć wszystkie następujące po niej wartości tablicy A o jedną komórkę w lewo oraz zmienić wartości wskaźników. Podobnie sprawa się ma z dodawaniem krawędzi.


Sposób 2 - Lista jednokierunkowa
     Sposób ten polega na utworzeniu dla każdego wierzchołka listy jednokierunkowej przechowującej jego sąsiadów. Lista taka to pewna struktura danych, która pozwala na na przyspieszenie pewnych operacji. Przykładowo: możemy usunąć dowolny element ze środka listy bez potrzeby przestawiania wszystkich jego następników. Przypominam, że jest to właśnie to co sprawiało, że poprzednia omówiona implementacja nie była zbyt dobra. Nie będę tłumaczył tutaj jak to dokładnie działa, gdyż wymagało by to szczegółowego omówienia list. Zachęcam jednak do przejrzenia innych źródeł i zapoznania się z tą strukturą danych.

I to by było na tyle...
     ...w tej części artykułu. W następnej części omówione zostaną dwa podstawowe algorytmy operujące na grafach: DFS i BFS. :)


Przejdź do następnej części
głosów: 5 | ocena: 8.19 oceń zasób | dodał: Platyna
Komentarze
Dodaj komentarz:
Treść:
Menu
Panel użytkownika
Jesteś niezalogowany!

Nie masz konta? Zarejestruj się
Użytkownicy on-line
106 użytkownik(ów) aktywny(ch) przez ostatnie 15 minut:
gości: 106, userów: 0, ukrytych: 0


0 użytkownik(ów) na gmczacie i 0 bot(ów)
Shoutbox
Chell (19:41, 22.03.17):
tez chetnie potestuje
owyn (14:12, 22.03.17):
Zrob aby tura zaczela sie w piatek to z checia cos zrobie
I am Lord (22:09, 21.03.17):
Co już chcecie kolejną turę?
Nikas (21:14, 21.03.17):
Nie fikaj za bardzo farfoclu!!!!
Threef (20:58, 21.03.17):
Jakieś bany trzeba dać? Bo mam dobry humor.
Threef (20:58, 21.03.17):
Oh damn! 2 tygodnie bez PC.
Wojo (20:50, 21.03.17):
za 12 godain
owyn (19:20, 21.03.17):
A kiedy kolejna tura ligi24???
Wojo (18:08, 21.03.17):
No to powodzenia tak czy inaczej
Gibki Kaktus (17:41, 21.03.17):
No ja mogę ograć XD
Nikas (16:28, 21.03.17):
Mam już grupkę testerów zawodowych z QA z mojej byłej pracy. Tutaj piszę, bo zawsze tu piszę.
Wojo (15:11, 21.03.17):
jak coś to też mogę pyknąć
Wojo (15:11, 21.03.17):
w sumie potrzebowałbyś więcej niż jednego typka z gmclanu do testów
Adriann (14:05, 21.03.17):
Ja chętnie przetestuję całość!
Ignatus (14:05, 21.03.17):
Stwierdzam własnie że nienawidze GM.Po raz n-ty w ostatnim miesiącu robie cos w grze i nagle przestaje dzialac cos co nie ma z tym żadnego zwiazku i robilem to miesiac temu.Zmieniam sobie parametry broni w grze i nagle BAM! Postac non stop kreci sie sama w kolko i nie wiem jak to zmienic.Piekny crap
Nikas (12:38, 21.03.17):
Nic nie płacę bo to są testy organizowane przeze mnie a nie AAG. Będzie miejsce w creditsach co może posłużyć jako normalny wpis do CV przy szukaniu pracy w QA. Chodzi tylko o ogranie gry, spisaniu odczuć (muszę zbalansować poziom trudności z samemu ciężko).
Gibki Kaktus (12:31, 21.03.17):
Ile płacisz? Jak >=0, to mogę ograć
Wojo (12:19, 21.03.17):
a co miałbym ci np tam spisać jakbym był chętny ?
Nikas (12:01, 21.03.17):
Szukam osoby chętnej na przetestowanie najthołxa. Tylko mówię tutaj o ograniu gry i spisaniu raportu, mam kluczyk do Steama. Ktoś chętny?
Nikas (23:14, 20.03.17):
Ale muszę przyznać, że dobra odpowiedź fervi. Szanuję.
Nikas (23:13, 20.03.17):
Tak, zobaczyłem tylko jakiś śmieszny cytat o wolności który wysłałeś i wyszedłem. xDDD ekstra gamedev
Fervi  (21:48, 20.03.17):
A co, dołączyłeś?
Nikas (11:30, 20.03.17):
Pewnie tam niezła stulejada. xDDD
Fervi  (20:39, 19.03.17):
#freegamer na freenode (dla wolnościowców, co zniechęca wiele osób )
owyn (14:05, 19.03.17):
jest jakis kanal irc nt. game-dev gdzie przesiadujecie?
Adriann (20:50, 18.03.17):
28-30 kwietnia
Wojo (20:34, 18.03.17):
a kiedy są te pyrkony ?
Gibki Kaktus (20:32, 18.03.17):
Jakim piwkiem, walimy wódę i moje urodziny oblewamy, każdy kto będzie na Pyrkonie!
I am Lord (19:55, 18.03.17):
Turmoil jest zrobiony w GMie :o
Adriann (19:41, 18.03.17):
to się skończy piwkiem, i to nie jednym:3
Ignatus (19:31, 18.03.17):
ja
Gibki Kaktus (19:25, 18.03.17):
Ja
ANtY (17:17, 18.03.17):
ja
Adriann (16:47, 18.03.17):
Miśki! Kto z was jedzie na Pyrkon?
PatrykPlayingPOLSKA (14:37, 18.03.17):
No elo Woju
Wojo (13:13, 18.03.17):
elo kuncu
Dester (15:33, 17.03.17):
Flashek (22:56, 16.03.17):
Dester robi wspaniałe gry
I am Lord (19:30, 16.03.17):
Słuchajcie bo mamy remis tutaj forum.gmclan.or...mp;#entry443228 i trzeba zrobić dogrywkę między Desterem a Chuckek, możecie napisać nowy post na kogo głosujecie? Poczekam na wyniki do północy z piątku na sobotę
Wojo (18:12, 16.03.17):
On nigdy nie odszedł. On zawsze mieszkał u nas w serduszkach
gnysek (16:43, 16.03.17):
On wrócił! Nawet nie pamietam już jaki miał nick... Paquo ?
Nikas (16:20, 16.03.17):
Jest klimat tamtych czasów, w sumie całkiem niezłe. na manieczkach, protektorze czy sunrisie by mogło wtedy hulać. xD
Ignatus (15:01, 16.03.17):
Ktos ma uszy odporne na techno-pierdy? Moje wypociny sprzed 10lat www.youtube.com...h?v=G5bWv-VBPUo
Wojo (13:42, 16.03.17):
www.youtube.com...h?v=t6PTzOClI5g kozackie rytmy. I pomyśleć, że mamy takich zdolnych userów
Wojo (13:36, 16.03.17):
Przecież tutaj rzadko kto pisze
Wojo (13:20, 16.03.17):
Szkoda, że już to forum umiera
gnysek (13:19, 16.03.17):
Ja miałem maskę admina ustawioną. Nikt więcej tak nie ma, bo Ranma zrobił porządki.
Wojo (13:17, 16.03.17):
Takich, którzy faktycznie mają rangę admina bo gnysek już jest userem a adminem był.
Ankieta
» Czy jesteś szczery odpowiadając w ankietach w Internecie?
Tak
Nie

GMCLAN to serwis o programie Game Maker i nie tylko.
Copyright © 2002-2017. GMCLAN.ORG
Wszelkie prawa zastrzeżone. Kopiowanie materiałów bez zgody redakcji zabronione!

[ Czas generowania strony: 0.00672 sekund ] [ Liczba zapytań MySQL: 14 ]

thecrims Otserv List Otserv LyricsTown Harry Potter Serwery Gier
dev nodev