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
40 użytkownik(ów) aktywny(ch) przez ostatnie 15 minut:
gości: 38, userów: 2, ukrytych: 0
ANtY, ediepl

0 użytkownik(ów) na gmczacie i 0 bot(ów)
Shoutbox
Wojo (12:55, 25.05.17):
Ale i tak niektórzy żyją we własnym świecie w którym Windows jest złem numer jeden
Wojo (12:50, 25.05.17):
Mam na myśli te pseudo doskonałe sposoby którymi nabijacie kabze spryciarzowi
Wojo (12:49, 25.05.17):
Ale fakt faktem znaczna większość sposobów na zarabianie w necie jest poprostu mało opłacalna. No chyba że chcecie sobie dorobić mając te szesnaście lat. Na dłuższą metę śmiesznie jest oglądać dorosłego człowieka który z klikania pół dnia w reklamy dysponuje pieniędzmi pokoju 500zl i jeszcze się rzuca
Wojo (12:46, 25.05.17):
Nawet się o taką pracę nie starałem. Twoja stara zajęła etat
Fervi  (12:26, 25.05.17):
Wiem, że za tańczenie na rurze więcej ci płacą, ale nie każdy ma takie możliwości
Wojo (8:46, 25.05.17):
500zl przy solidnej pracy xD na 500zl to mi się nawet nie chce
Fervi  (22:39, 24.05.17):
Oczywiście nie mówię, by porzucić stare strony, tylko po prostu dołączyć do kolejnej
Fervi  (22:34, 24.05.17):
Oczywiście drugiej pensi na tym nie zbudujecie, ale z 500zł przy solidnej pracy
Fervi  (22:30, 24.05.17):
Moje bitcoiny nie zgadzają się z tobą xD
Wojo (22:13, 24.05.17):
To nie zadziała. Macie moje słowo
I am Lord (21:45, 24.05.17):
tak i dać nrgeekowi do zrecenzowania :p
Fervi  (21:00, 24.05.17):
Mógłbyś Kacz De Klałna w big box produkować
Fervi  (20:58, 24.05.17):
I admini GMClanu tańczą dla twojej przyjemności, a tak to lipa, po ptokach
Fervi  (20:58, 24.05.17):
Dziwactwo, ale gdyby kopać to wtedy, to dziś mieszkasz na karaibach
Fervi  (20:57, 24.05.17):
No wiesz, cała informatyka to dziwactwo. Ot taki Bitcoin
Fervi  (20:57, 24.05.17):
W zależności jak cię ludzie lubią
Fervi  (20:57, 24.05.17):
Dostajesz kryptowalutę Steem / Steem Dollars
I am Lord (20:26, 24.05.17):
Fervex zawsze jakieś dziwactwo wynajdziesz
I am Lord (20:24, 24.05.17):
O co z tym chodzi?
PatrykPlayingPOLSKA (18:19, 24.05.17):
@Fervi Gdy wpisałem sobie Steem do przeglądarki i poczytałem co nieco,wtedy się zczaiłem że nie chodzi o Steama (falcepalm)
Fervi  (17:45, 24.05.17):
Brzmi jak dobry Scam, ale działa
Fervi  (17:45, 24.05.17):
Portal a'la Reddit, w którym płacą ci za treści (w skrócie)
Fervi  (17:45, 24.05.17):
@PatrykPlayingPOLSKA: Chodzi o Steem, nie Steam
Fervi  (17:45, 24.05.17):
@Wojo - i dobrze, ja sobie odkładam hajs ze Steem
PatrykPlayingPOLSKA (15:37, 24.05.17):
Wydaje mi się że GMC na już grupę na steamie,a nawet dwie.
Wojo (15:25, 24.05.17):
Ten pomysł brzmi tak rozsądnie jak instalacja linuxa
Fervi  (15:05, 24.05.17):
Może powinniśmy przejść na Steem / (niebawem) Strimi? Można zarobić, a przy okazji zrobić grupę gejclanu
nowy_user (8:50, 23.05.17):
Dzięki już działa, rzeczywiscie umknęła mi opcja erase a colour , jest idealna do mojego problemu
I am Lord (18:10, 22.05.17):
A tak w ogóle to gumce też można rozmiar zwiększyć, tylko że ona ma miękkie krawędzie
I am Lord (18:08, 22.05.17):
aha Opacity na 0 jeszcze
I am Lord (18:08, 22.05.17):
Masz tak się to robi: i.imgur.com/IDtZODf.png
I am Lord (18:02, 22.05.17):
Nie wierzę co czytam
Uzjel (16:35, 22.05.17):
Aj ludzie, problemy se robicie
gnysek (16:34, 22.05.17):
GIMP ma przeźroczyste tła. GMS 1.x ma funkcję "make opaque", a GMS2 ma różdżkę która zaznacza na raz 1 kolor wszędzie (contignous).
Ignatus (16:16, 22.05.17):
Wlasnie GM ma funkcje ktorej mi w programach graficznych brakuje (albo nie wiem jak znalezc) "Erase a color"
nowy_user (15:46, 22.05.17):
Zaznaczanie róźdżką też jest strasznie toporne. No nie wierzę że w gm sudio nie ma innego sposobu. Przecież są ludzie, którxy tworzą grafiki np. w gimpie lub paincie, i nine chce mi się wierzyć że za każdym razem usuwają białe tło piksel po pikselu. Przecież to niedorzeczne.
nowy_user (15:26, 22.05.17):
gm studio 1 ; ehhh w gm 5.3 nie bylo problemu , tlo bylo lewym dolnym rogiem
gnysek (15:22, 22.05.17):
Ktory GM tak w ogóle?
gnysek (15:22, 22.05.17):
To zaznacz różdzką
nowy_user (15:07, 22.05.17):
Niestety przy 100% przezroczystosci, farba ,maluje na czarno, a zaznaczenie + delete owszem działa ale tylko na prostokątnych powierzzchniach. Dalej nie działa to tak jak trzeba
ANtY (13:05, 22.05.17):
spróbuj zaznaczenie + delete, jak pomoglem to daj okejke
gnysek (11:11, 22.05.17):
To weź farbę i ustaw 100% przeźroczystą
nowy_user (11:06, 22.05.17):
tak tylko że gumką muszę tak prezycyjnie piksel po pikselu, a ja chce cały obszar ograniczony konturami, tak samo jak farbą w paincie
ANtY (10:51, 22.05.17):
gumką
nowy_user (10:09, 22.05.17):
hej , jak zamalować tło na przezroczyste w edytorze spritow w game maker?
I am Lord (15:38, 21.05.17):
site:gmclan.org w google
BloodDzioch (14:39, 21.05.17):
Gdzie na community jest jakaś wyszukiwarka? Za cholery nie mogę znaleźć
Adriann (10:36, 21.05.17):
To odpada, potrzebuję czegoś animowanego pomiędzy
Threef (10:29, 21.05.17):
Nie da się. Możesz wstawić [1] pomiędzy [0] a [2], ale żadnych obiektów nie wsadzisz. Ona mają depth, ale silnik chyba rysuje je osobno. Możesz za to rysować draw_background()
Adriann (22:53, 20.05.17):
Tznnnn chcę umieścić jakiś obiekt między backgrond[0] a [1]
Ankieta
» Jakiej wersji GameMakera głównie Używasz?
GameMaker: Studio 2
GameMaker: Studio
GameMaker 8.1 i starsze
Żadnej

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.00818 sekund ] [ Liczba zapytań MySQL: 14 ]

thecrims Otserv List Otserv LyricsTown Harry Potter Serwery Gier
dev nodev