Lista sąsiedztwa i macierzowa reprezentacja wykresu

⚡ Inteligentne podsumowanie

Lista sąsiedztwa i macierzowa reprezentacja grafu przechowują wierzchołki i krawędzie w pamięci, umożliwiając algorytmom przechodzenie przez sieci. Lista sąsiedztwa wykorzystuje listy powiązane dla każdego wierzchołka, natomiast macierz sąsiedztwa wykorzystuje kwadratową, dwuwymiarową siatkę.

  • 📐 Lista sąsiedztwa: Tablica list powiązanych V, w której każda lista o indeksie i przechowuje każdy wierzchołek sąsiadujący z wierzchołkiem i, zapewniając O(V + E) pamięci.
  • 🗺️. Macierz sąsiedztwa: Dwuwymiarowa tablica AV × V, gdzie macierz[i][j] przechowuje wagę krawędzi lub 1, gdy krawędź istnieje pomiędzy wierzchołkiem i i wierzchołkiem j.
  • Szybkość wyszukiwania: Macierz sąsiedztwa odpowiada na pytanie „czy istnieje krawędź między i i j?” w czasie O(1), podczas gdy lista sąsiedztwa potrzebuje czasu O(stopnia) na przeskanowanie listy sąsiadów.
  • 💾 Pamięć: Macierz sąsiedztwa zawsze zużywa O(V²) pamięci, nawet w przypadku rzadkich grafów, podczas gdy lista sąsiedztwa skaluje się wraz z rzeczywistą liczbą krawędzi.
  • 🔍 Najlepsze dopasowanie: Wybierz macierz sąsiedztwa dla gęstych grafów z częstymi zapytaniami o krawędzie, a listę sąsiedztwa dla rzadkich grafów i obciążeń wymagających intensywnego przechodzenia.
  • 🛠️. Aplikacje: Obie reprezentacje obsługują potoki BFS, DFS, Dijkstry, PageRank, routingu sieci dróg i sieci neuronowych grafów stosowane w systemach sztucznej inteligencji.

Lista sąsiedztwa i macierzowa reprezentacja wykresu

Mimo że wyglądają inaczej, wszyscy rodzaje wykresów można przedstawić w podobny sposób. Istnieją dwa rodzaje reprezentacji graficznej:

  1. Macierz sąsiedztwa
  2. Lista sąsiedztwa

Lista sąsiedztwa

Lista sąsiedztwa składa się z list powiązanych. Każdy wierzchołek jest traktowany jako indeks tablicy, a każdy element reprezentuje listę powiązaną. Te listy powiązane zawierają wierzchołki, które mają wspólną krawędź z wierzchołkiem indeksowanym.

Oto przykład listy sąsiedztwa:

Lista sąsiedztwa

Niech graf zawiera V wierzchołków i E krawędzi. Złożoność przestrzenna listy sąsiedztwa wynosi O(V + E), który skaluje się wraz z liczbą rzeczywistych krawędzi, a nie każdej możliwej pary wierzchołków.

W najgorszym przypadku złożoność przestrzeni staje się O(V²) jeśli dany graf jest grafem zupełnym, ponieważ każdy wierzchołek łączy się z każdym innym wierzchołkiem.

Macierz sąsiedztwa

Macierz sąsiedztwa składa się z tablicy 2D. W przypadku grafu z V wierzchołkami rozmiar macierzy będzie wynosił V × V.

Mówić matrix[i][j] = 5Oznacza to, że istnieje krawędź pomiędzy węzłem i i węzłem j, której waga wynosi 5.

Przyjrzyjmy się poniższemu grafowi i jego macierzy sąsiedztwa:

Macierz sąsiedztwa

Zbudowaliśmy Tablica 2D korzystając z tych kroków:

Krok 1) Wierzchołek A ma bezpośrednią krawędź z wierzchołkiem B, a waga wynosi 5. Zatem komórka w wierszu A i kolumnie B zostanie wypełniona wartością 5. Pozostałe komórki w wierszu A zostaną wypełnione wartością zerową.

Krok 2) Wierzchołek B ma bezpośrednią krawędź z C, a waga wynosi 4. Zatem komórka w wierszu B i kolumnie C zostanie wypełniona wartością 4. Pozostałe komórki w wierszu B zostaną wypełnione wartością zerową, ponieważ B nie ma krawędzi wychodzącej do żadnego innego węzła.

Krok 3) Wierzchołek C nie ma krawędzi bezpośrednich z żadnym innym wierzchołkiem. Dlatego wiersz C zostanie wypełniony zerami.

Krok 4) Wierzchołek D ma skierowaną krawędź z A i C.

  • Komórka w wierszu D i kolumnie A będzie miała wartość 7. Komórka w wierszu D i kolumnie C będzie miała wartość 2.
  • Pozostałe komórki w wierszu D zostaną wypełnione zerami.

Krok 5) Wierzchołek E ma skierowaną krawędź z B i D. Komórka w wierszu E i kolumnie B będzie miała wartość 6. Komórka w wierszu E i kolumnie D będzie miała wartość 3. Pozostałe komórki w wierszu E będą wypełnione zerami.

Oto kilka punktów, na które warto zwrócić uwagę:

  • Graf nie posiada pętli własnych, gdy przekątna główna macierzy sąsiedztwa jest równa 0.
  • Graf jest grafem skierowanym, jeśli komórki w punktach (a, b) i (b, a) nie mają tej samej wartości. W przeciwnym razie graf jest nieskierowany.
  • Wykres jest wykresem ważonym, jeżeli wartość dowolnej komórki jest większa od 1.

Głównym problemem macierzy sąsiedztwa jest to, że wymaga ona kwadratowej przestrzeni. Nawet nieistniejące krawędzie nadal przydzielają komórki w pamięci.

Na przykład, jeśli mamy graf z 100 węzłami, to do jego zapisania potrzeba 10 000 komórek. RAMPrzy mniejszej liczbie krawędzi w grafie przydzielanie tak dużej ilości pamięci może być marnotrawstwem. Zatem złożoność pamięci przy użyciu macierzy sąsiedztwa wynosi O(N²), gdzie N jest liczbą węzłów na grafie.

Lista sąsiedztwa kontra macierz sąsiedztwa

Przed wybraniem reprezentacji warto porównać oba modele obok siebie w odniesieniu do operacji dominujących w rzeczywistych obciążeniach grafów:

OperacjaMacierz sąsiedztwaLista sąsiedztwa
Złożoność przestrzeniO(V²)O(V + E)
Dodaj wierzchołekO(V²)O (1)
Dodaj krawędźO (1)O (1)
Usuń krawędźO (1)O(E)
Sprawdź czy krawędź (i, j) istniejeO (1)O(stopień i)
Iteruj po sąsiadach iO (V)O(stopień i)
Najlepszy dlaGęste grafy, częste zapytania krawędzioweRzadkie grafy, zadania wymagające intensywnego przechodzenia

Krótko mówiąc, macierz sąsiedztwa wygrywa w przypadku wyszukiwań krawędzi w stałym czasie, natomiast lista sąsiedztwa wygrywa w przypadku iteracji pamięci i sąsiadów, dlatego algorytmy takie jak BFS, DFS i Dijkstra zwykle łączą się z listami sąsiedztwa.

Zalety i wady reprezentacji grafowej

Każda reprezentacja niesie ze sobą pewne kompromisy. Znajomość mocnych i słabych stron obu modeli pomoże Ci wybrać ten właściwy dla rozwiązywanego problemu.

Zalety macierzy sąsiedztwa:

  • Zapytania o istnienie krawędzi w czasie stałym O(1) pomiędzy dowolną parą wierzchołków.
  • Stałe indeksowanie ułatwia implementację algorytmów macierzowych, takich jak algorytm Floyda-Warshalla i domknięcie przechodnie.
  • Obciążone krawędzie naturalnie pasują do pojedynczej komórki macierzy.

Wady macierzy sąsiedztwa:

  • Marnuje O(V²) pamięci, gdy graf jest rzadki.
  • Dodanie nowego wierzchołka wymaga zmiany rozmiaru całej macierzy.
  • Iterowanie po sąsiadujących wierzchołkach zajmuje O(V) nawet wtedy, gdy wierzchołek ma tylko kilka krawędzi.

Zalety listy sąsiedztwa:

  • Używa tylko pamięci O(V + E), co jest wartością zbliżoną do rzeczywistej liczby krawędzi w rzadkich grafach.
  • Dodanie nowego wierzchołka lub krawędzi to O(1).
  • Algorytmy przechodzenia, takie jak BFS i DFS, iterują po sąsiadach z dokładnością O(stopni), co daje łączny czas wykonania O(V + E).

Wady listy sąsiedztwa:

  • Sprawdzenie, czy dana krawędź istnieje, zajmuje czas O(stopni) zamiast O(1).
  • Lokalność pamięci podręcznej jest słabsza, ponieważ listy powiązane są rozproszone w pamięci.
  • Krawędzie ważone wymagają pola towarzyszącego lub listy par, co nieco komplikuje strukturę danych.

Kiedy używać listy sąsiedztwa, a kiedy macierzy sąsiedztwa

Wybór reprezentacji zależy od gęstości grafu i najczęściej wykonywanych operacji. Skorzystaj z tego krótkiego przewodnika, aby wybrać odpowiednią strukturę:

  • Preferuj macierz sąsiedztwa gdy graf jest gęsty (E jest bliskie V²), gdy krawędzie rzadko się zmieniają i gdy algorytm wielokrotnie pyta „czy istnieje krawędź między i i j?”.
  • Preferuj listę sąsiedztwa gdy graf jest rzadki (E jest znacznie mniejsze niż V²), gdy zbiór wierzchołków lub krawędzi rośnie podczas wykonywania i gdy przemierzasz graf metodą BFS, DFS lub Algorytm najkrótszej ścieżki Dijkstry.
  • Wolę model mieszany (lista sąsiedztwa plus zestaw skrótów krawędzi), gdy potrzebujesz zarówno szybkiej iteracji sąsiedztwa, jak i zapytań o krawędzie O(1), ale kosztem dodatkowej pamięci.

Nowoczesne biblioteki grafów, takie jak NetworkX i igraph, domyślnie korzystają z list sąsiedztwa, ponieważ większość rzeczywistych grafów — sieci społecznościowe, mapy drogowe, strony internetowe, zależności pakietów — jest rozproszona i wymaga intensywnego przeglądania.

FAQ

Lista sąsiedztwa to tablica V list powiązanych, w której każda lista o indeksie i przechowuje każdy wierzchołek sąsiadujący z wierzchołkiem i. Zużycie pamięci wynosi O(V + E), co jest odpowiednie dla grafów rzadkich i algorytmów przechodzenia, takich jak BFS i DFS.

Macierz sąsiedztwa to dwuwymiarowa tablica V × V, w której macierz[i][j] przechowuje wagę krawędzi lub 1, jeśli krawędź istnieje pomiędzy wierzchołkiem i i wierzchołkiem j. Przeszukiwanie krawędzi to O(1), ale pamięć to zawsze O(V²).

Macierz sąsiedztwa odpowiada na zapytania o istnienie krawędzi w tempie O(1). Lista sąsiedztwa iteruje sąsiadów w tempie O(stopnia), co jest szybsze w przypadku algorytmów przechodzenia, takich jak BFS, DFS i Dijkstra. Najlepszy wybór zależy od operacji dominujących w danym obciążeniu.

Użyj listy sąsiedztwa, gdy graf jest rzadki, gdy wierzchołki i krawędzie zmieniają się podczas wykonywania oraz gdy algorytm często przechodzi przez sąsiednie obiekty. Sieci społecznościowe, mapy drogowe i grafy stron internetowych pasują do tego profilu.

Użyj macierzy sąsiedztwa, gdy graf jest gęsty, gdy zbiór wierzchołków jest stały oraz gdy algorytm wielokrotnie odpytuje tę samą krawędź. Macierze Floyda-Warshalla i domknięcie przechodnie działają naturalnie na macierzach sąsiedztwa.

Tak. W przypadku grafów skierowanych macierz nie jest symetryczna, a lista przechowuje tylko sąsiadów wychodzących. W przypadku grafów ważonych komórka macierzy przechowuje wagę, podczas gdy lista przechowuje pary sąsiadów i wag.

Sieci neuronowe grafów dostarczają macierze sąsiedztwa lub rzadkie tensory krawędzi do warstw uczenia maszynowego w celu wykrywania oszustw, przewidywania właściwości cząsteczek i systemów rekomendacji. Grafy wiedzy wykorzystują również kodowanie list sąsiedztwa w sztucznej inteligencji wspomaganej wyszukiwaniem.

Tak. GitHub Copilot i ChatGPT generują listę sąsiedztwa i szablon macierzy dla Python, C++, JavaProgramiści muszą nadal weryfikować przypadki brzegowe, takie jak zduplikowane krawędzie, pętle własne i poprawną obsługę grafów skierowanych lub ważonych.

Podsumuj ten post następująco: