Serwis Edukacyjny w I-LO w Tarnowie Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej Autor artykułu: mgr Jerzy Wałaszek |
©2024 mgr Jerzy Wałaszek |
Do reprezentacji
grafów
w pamięci komputera wymyślono kilka różnych struktur danych.
Każda z nich posiada swoje zalety, lecz również wady. Dlatego
należy je rozsądnie dobierać do zadań, w których używamy grafów.
Źle dobrana reprezentacja może znacząco wydłużyć czas obliczeń
lub rozmiar zajmowanej pamięci. Graf zwykle nie jest strukturą
hierarchiczną, jak np. opisane wcześniej drzewa. Jego węzły nie muszą się ze sobą
łączyć w określony sposób. Mogą również istnieć grupy węzłów,
które nie są w żaden sposób połączone z innymi. Dlatego sposoby
reprezentacji drzew niezbyt nadają się do reprezentacji grafów,
które powinny zapewniać dostęp do wszystkich wierzchołków bez
względu na ich wzajemne połączenia krawędziami. Takie cechy
posiadają tablice i macierze. W rozdziale tym omawiamy trzy
najczęściej spotykane sposoby przedstawiania grafów: macierz sąsiedztwa
(ang. adjacency
matrix), macierz incydencji (ang. incidence matrix)
oraz listy sąsiedztwa (ang. adjacency lists).
Cechą charakterystyczną tych implementacji jest wykorzystanie
tablic do przechowywania informacji na temat wierzchołków lub
łączących je krawędzi. Wykorzystuje się również struktury
mieszane, np. tablicę, której elementami są listy. |
Chcąc realizować algorytmy grafowe, będziemy zmuszeni wprowadzać różne grafy do pamięci komputera. Istnieje bardzo prosty sposób realizacji tego zadania i jest on następujący:
Na początku podajemy dwie liczby: n – ilość
wierzchołków oraz
m – ilość
krawędzi. Następnie
wprowadzamy m par
5 6 | – 5 wierzchołków i 6 krawędzi | |
0 1 | – krawędź e0 | |
1 2 | – krawędź e1 | |
2 3 | – krawędź e2 | |
3 0 | – krawędź e3 | |
1 4 | – krawędź e4 | |
3 4 | – krawędź e5 |
Jeśli krawędzie będą posiadały wagi, to wartości tych wag podamy jako trzecią liczbę w definicji krawędzi.
5 6 | – 5 wierzchołków i 6 krawędzi | |
0 1 5 | – krawędź e0 i jej waga | |
1 2 -3 | – krawędź e1 i jej waga | |
2 3 0 | – krawędź e2 i jej waga | |
3 0 -1 | – krawędź e3 i jej waga | |
1 4 2 | – krawędź e4 i jej waga | |
3 4 4 | – krawędź e5 i jej waga |
Jeśli z wierzchołkami grafu zechcemy skojarzyć dane, to po podaniu dwóch pierwszych liczb n i m najpierw przekazujemy do programu n danych dla wierzchołków, a następnie m par (lub trójek) dla poszczególnych krawędzi.
5 6 | – 5 wierzchołków i 6 krawędzi | |
5 | – dane dla v0 | |
3 | – dane dla v1 | |
1 | – dane dla v2 | |
6 | – dane dla v3 | |
8 | – dane dla v4 | |
0 1 | – krawędź e0 | |
1 2 | – krawędź e1 | |
2 3 | – krawędź e2 | |
3 0 | – krawędź e3 | |
1 4 | – krawędź e4 | |
3 4 | – krawędź e5 |
Graf reprezentujemy za pomocą macierzy kwadratowej A o stopniu n, gdzie n oznacza liczbę wierzchołków w grafie. Macierz taką nazywamy macierzą sąsiedztwa (ang. adjacency matrix). Odwzorowuje ona połączenia wierzchołków krawędziami. Wiersze macierzy sąsiedztwa odwzorowują zawsze wierzchołki startowe krawędzi, a kolumny odwzorowują wierzchołki końcowe krawędzi. Komórka A[i,j], która znajduje się w i-tym wierszu i j-tej kolumnie, odwzorowuje krawędź łączącą wierzchołek startowy vi z wierzchołkiem końcowym vj. Jeśli A[i,j] ma wartość 1, to dana krawędź istnieje. Jeśli A[i,j] ma wartość 0, to wierzchołek vi nie łączy się krawędzią z wierzchołkiem vj.
|
Dla grafu nieskierowanego macierz sąsiedztwa A
jest symetryczna względem głównej przekątnej, ponieważ jeśli
istnieje krawędź od vi do vj
|
Interpretacja zawartości macierzy sąsiedztwa jest bardzo prosta. Poszczególne wiersze traktujemy jako wierzchołki grafu. Zatem wiersz 0 odpowiada wierzchołkowi v0 wiersz 1 odpowiada wierzchołkowi v1, itd. Weźmy dla przykładu wiersz nr 3, który odpowiada wierzchołkowi v3:
0 | 1 | 2 | 3 | 4 | |
3 | 1 | 0 | 1 | 0 | 1 |
W kolumnach o numerach 0, 2 i 4 mamy wartości 1. Oznacza to, że wierzchołek v3 jest połączony krawędziami kolejno z wierzchołkami v0, v2 i v4. Wierzchołek v3 jest początkiem tych krawędzi, a wierzchołki v0, v2 i v4 są ich końcami. Z wierzchołka v3 nie wychodzą żadne krawędzie do wierzchołków v1 i v3. Porównaj to z rysunkiem grafu umieszczonym powyżej.
Podobnie jest dla kolumn. Weźmy na przykład kolumnę nr 1, która odpowiada wierzchołkowi v1:
1 | |
0 | 1 |
1 | 0 |
2 | 1 |
3 | 0 |
4 | 1 |
W kolumnie mamy wartość 1 w wierszach
Aby sprawdzić, czy w grafie dane dwa wierzchołki
vi
i vj są połączone krawędzią, sprawdzamy,
czy komórka
Z macierzy sąsiedztwa można odczytać wiele pożytecznych informacje. Oto niektóre z nich:
Uwaga: Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
Program odczytuje definicję grafu skierowanego, tworzy macierz sąsiedztwa i wypisuje ją w czytelnej formie. |
Dane przykładowe (przekopiuj je do schowka, a następnie wklej do okna konsoli):
|
Pascal// Macierz sąsiedztwa // Data: 14.07.2013 // (C)2013 mgr Jerzy Wałaszek //--------------------------- program adj_matrix; // Typy dla dynamicznej macierzy type nptr = array of byte; // Wiersz mptr = array of nptr; // Cała macierz var n, m, i, j, v1, v2 : integer; A : mptr = ((0)); // Macierz sąsiedztwa begin // Czytamy liczbę wierzchołków i krawędzi read(n, m); // Tworzymy tablicę wskaźników SetLength(A, n); for i := 0 to n-1 do // Tworzymy wiersze SetLength(A[i], n); // Macierz wypełniamy zerami for i := 0 to n-1 do for j := 0 to n-1 do A[i][j] := 0; // Odczytujemy kolejne definicje krawędzi for i := 1 to m do begin // Wierzchołek startowy i końcowy krawędzi read(v1, v2); // Krawędź v1->v2 obecna A[v1][v2] := 1; end; writeln; // Wypisujemy zawartość macierzy sąsiedztwa write(' '); for i := 0 to n-1 do write (i:3); writeln; writeln; for i := 0 to n-1 do begin write (i:3); for j := 0 to n-1 do write(A[i][j] :3); writeln; end; // Usuwamy macierz for i := 0 to n-1 do SetLength(A[i], 0); SetLength(A,0); writeln; end. |
// Macierz sąsiedztwa // Data: 14.07.2013 // (C)2013 mgr Jerzy Wałaszek //--------------------------- #include <iostream> #include <iomanip> using namespace std; int main() { int n, m, i, j, v1, v2; char ** A; // Macierz sąsiedztwa // Czytamy liczbę wierzchołków i krawędzi cin >> n >> m; // Tworzymy tablicę wskaźników A = new char * [n]; for(i = 0; i < n; i++) // Tworzymy wiersze A[i] = new char [n]; // Macierz wypełniamy zerami for(i = 0; i < n; i++) for(j = 0; j < n; j++) A[i][j] = 0; // Odczytujemy kolejne definicje krawędzi for(i = 0; i < m; i++) { // Wierzchołek startowy i końcowy krawędzi cin >> v1 >> v2; // Krawędź v1->v2 obecna A [v1][v2] = 1; } cout << endl; // Wypisujemy zawartość macierzy sąsiedztwa cout << " "; for(i = 0; i < n; i++) cout << setw(3) << i; cout << endl << endl; for(i = 0; i < n; i++) { cout << setw(3) << i; for(j = 0; j < n; j++) cout << setw(3) << (int)A[i][j]; cout << endl; } // Usuwamy macierz for(i = 0; i < n; i++) delete [] A[i]; delete [] A; cout << endl; return 0;} |
Basic' Macierz sąsiedztwa ' Data: 14.07.2013 ' (C)2013 mgr Jerzy Wałaszek '--------------------------- Dim As Integer n, m, i, j, v1, v2 Dim As Byte Ptr Ptr A Open Cons For Input As #1 ' Czytamy liczbę wierzchołków i krawędzi Input #1, n, m ' Tworzymy tablicę wskaźników A = New Byte Ptr [n] For i = 0 To n-1 ' Tworzymy wiersze A[i] = New Byte [n] Next ' Macierz wypełniamy zerami For i = 0 To n-1 For j = 0 To n-1 A[i][j] = 0 Next Next ' Odczytujemy kolejne definicje krawędzi For i = 0 To m-1 ' Wierzchołek startowy i końcowy krawędzi Input #1, v1, v2 ' Krawędź v1->v2 obecna A[v1][v2] = 1 Next Close #1 Print ' Wypisujemy zawartość macierzy sąsiedztwa Print " "; For i = 0 To n-1 Print Using "###";i; Next Print: Print For i = 0 To n-1 Print Using "###";i; For j = 0 To n-1 Print Using "###";A[i][j]; Next Print Next ' Usuwamy macierz For i = 0 To n-1 Delete [] A[i] Next Delete [] A Print End |
Python
(dodatek)# Macierz sąsiedztwa # Data: 23.11.2024 # (C)2024 mgr Jerzy Wałaszek #--------------------------- # Czytamy liczbę wierzchołków i krawędzi x = input().split() n = int(x[0]) m = int(x[1]) # Tworzymy macierz a[n][n] # wypełnioną samymi zerami a = [] for i in range(n): x = [] # Pusty wiersz macierzy for j in range(n): x.append(0) # Będzie n zer w wierszu a.append(x) # Wiersz dołączamy do macierzy # Odczytujemy kolejne definicje krawędzi for i in range(m): x = input().split() # Dwa wierzchołki v1 = int(x[0]) # Start v2 = int(x[1]) # Koniec a[v1][v2] = 1 # Krawędź v1->v2 obecna print() # Wypisujemy zawartość macierzy sąsiedztwa print(" ", end="") for i in range(n): print("%3d" % i, end="") print() print() for i in range(n): print("%3d" % i, end="") for j in range(n): print("%3d" % a[i][j], end="") print() # Usuwamy macierz del a print() |
Wynik: |
6 8 0 1 1 2 2 2 1 3 3 1 2 4 4 0 4 3 0 1 2 3 4 5 0 0 1 0 0 0 0 1 0 0 1 1 0 0 2 0 0 1 0 1 0 3 0 1 0 0 0 0 4 1 0 0 1 0 0 5 0 0 0 0 0 0 |
Macierz incydencji (ang. incidence matrix)
jest macierzą A o wymiarze
|
Jeśli graf jest nieskierowany, to definicję macierzy można uprościć:
|
Interpretacja macierzy incydencji jest równie prosta jak
interpretacja macierzy sąsiedztwa. Weźmy dla przykładu wiersz
0 | 1 | 2 | 3 | 4 | 5 | |
3 | 0 | 0 | -1 | 1 | 0 | 1 |
Wiersz nr 3 skojarzony jest z wierzchołkiem v3 grafu. Wierzchołek v3 jest końcem krawędzi e2 oraz początkiem krawędzi e3 i e5. Nie należy do krawędzi e0, e1 i e4.
Z kolei każda kolumna odwzorowuje jedną krawędź. Weźmy kolumnę
2 | |
0 | 0 |
1 | 0 |
2 | 1 |
3 | -1 |
4 | 0 |
Kolumna nr 2 skojarzona jest z krawędzią e2 grafu. Krawędź ta wychodzi od wierzchołka v2 i kończy się w wierzchołku v3.
Macierz incydencji wymaga pamięci o rozmiarze
Z macierzy incydencji możemy odczytać te same informacje, co z macierzy sąsiedztwa (chociaż czasami wymaga to więcej działań).
Uwaga: Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
Program odczytuje definicję grafu skierowanego, tworzy macierz incydencji i wypisuje ją w czytelnej formie. |
Dane przykładowe (przekopiuj do schowka i
wklej do okna konsoli):
|
Pascal// Macierz incydencji // Data: 18.07.2013 // (C)2013 mgr Jerzy Wałaszek //--------------------------- program inc_matrix; // Typy dla dynamicznej macierzy type nptr = array of shortint; // Wiersz mptr = array of nptr; // Cała macierz var n, m, i, j, v1, v2 : integer; A : mptr; begin // Czytamy liczbę wierzchołków i krawędzi read(n, m); // Tworzymy tablicę wskaźników SetLength(A, n); for i := 0 to n-1 do SetLength (A [i], m); // Tworzymy wiersze // Macierz wypełniamy zerami for i := 0 to n-1 do for j := 0 to m-1 do A [i][j] := 0; // Odczytujemy kolejne definicje krawędzi for i := 0 to m-1 do begin // Wierzchołek startowy i końcowy krawędzi read(v1, v2); A[v1][i] := 1; // Wierzchołek startowy A[v2][i] := -1; // Wierzchołek końcowy end; writeln; // Wypisujemy zawartość macierzy incydencji write(' '); for i := 0 to m-1 do write (i:3); writeln; writeln; for i := 0 to n-1 do begin write (i:3); for j := 0 to m-1 do write(A[i][j]:3); writeln; end; // Usuwamy macierz for i := 0 to n-1 do SetLength(A[i], 0); SetLength(A, 0); writeln; end. |
// Macierz incydencji // Data: 18.07.2013 // (C)2013 mgr Jerzy Wałaszek //--------------------------- #include <iostream> #include <iomanip> using namespace std; int main() { int n, m, i, j, v1, v2; signed char ** A; // Czytamy liczbę wierzchołków i krawędzi cin >> n >> m; // Tworzymy tablicę wskaźników A = new signed char * [n]; for(i = 0; i < n; i++) // Tworzymy wiersze A[i] = new signed char [m]; // Macierz wypełniamy zerami for(i = 0; i < n; i++) for(j = 0; j < m; j++) A [i][j] = 0; // Odczytujemy kolejne definicje krawędzi for(i = 0; i < m; i++) { // Wierzchołek startowy i końcowy krawędzi cin >> v1 >> v2; A[v1][i] = 1; // Wierzchołek startowy A[v2][i] = -1; // Wierzchołek końcowy } cout << endl; // Wypisujemy zawartość macierzy incydencji cout << " "; for(i = 0; i < m; i++) cout << setw(3) << i; cout << endl << endl; for(i = 0; i < n; i++) { cout << setw(3) << i; for(j = 0; j < m; j++) cout << setw(3) << (int)A[i][j]; cout << endl; } // Usuwamy macierz for(i = 0; i < n; i++) delete [] A[i]; delete [] A; cout << endl; return 0; } |
Basic' Macierz incydencji ' Data: 18.07.2013 ' (C)2013 mgr Jerzy Wałaszek '--------------------------- Dim As Integer n, m, i, j, v1, v2 Dim As Byte Ptr Ptr A Open Cons For Input As #1 ' Czytamy liczbę wierzchołków i krawędzi Input #1, n, m ' Tworzymy tablicę wskaźników A = New Byte Ptr [n] For i = 0 To n-1 A[i] = New Byte [m] ' Tworzymy wiersze Next ' Macierz wypełniamy zerami For i = 0 To n-1 For j = 0 To m-1 A[i][j] = 0 Next Next ' Odczytujemy kolejne definicje krawędzi For i = 0 To m-1 ' Wierzchołek startowy i końcowy krawędzi Input #1, v1, v2 A[v1][i] = 1 ' Wierzchołek startowy A[v2][i] = -1 ' Wierzchołek końcowy Next Close #1 Print ' Wypisujemy zawartość macierzy incydencji Print " "; For i = 0 To m-1 Print Using "###";i; Next Print: Print For i = 0 To n-1 Print Using "###";i; For j = 0 To m-1 Print Using "###";A[i][j]; Next Print Next ' Usuwamy macierz For i = 0 To n-1 Delete [] A[i] Next Delete [] A Print End |
Python
(dodatek)# Macierz incydencji # Data: 25.11.2024 # (C)2024 mgr Jerzy Wałaszek #--------------------------- # Czytamy liczbę wierzchołków i krawędzi x = input().split() n = int(x[0]) m = int(x[1]) # Tworzymy macierz a = [] for i in range(n): x = [] for j in range(m): x.append(0) a.append(x) # Odczytujemy kolejne definicje krawędzi for i in range(m): # Wierzchołek startowy i końcowy krawędzi x = input().split() v1 = int(x[0]) v2 = int(x[1]) a[v1][i] = 1 # Wierzchołek startowy a[v2][i] = -1 # Wierzchołek końcowy print() # Wypisujemy zawartość macierzy incydencji print(" ", end="") for i in range(m): print("%3d" % i, end="") print() print() for i in range(n): print("%3d" % i, end="") for j in range(m): print("%3d" % a[i][j], end="") print() # Usuwamy macierz del a print() |
Wynik: |
6 7 0 1 1 2 1 3 3 1 2 4 4 0 4 3 0 1 2 3 4 5 6 0 1 0 0 0 0 -1 0 1 -1 1 1 -1 0 0 0 2 0 -1 0 0 1 0 0 3 0 0 -1 1 0 0 -1 4 0 0 0 0 -1 1 1 5 0 0 0 0 0 0 0 |
Do reprezentacji grafu wykorzystujemy tablicę n elementową A, gdzie n oznacza liczbę wierzchołków. Każdy element tej tablicy jest listą. Lista reprezentuje wierzchołek startowy. Na liście są przechowywane numery wierzchołków końcowych, czyli sąsiadów wierzchołka startowego, z którymi jest on połączony krawędzią. Tablica ta nosi nazwę list sąsiedztwa (ang. adjacency lists).
|
W przypadku grafu nieskierowanego listy są dłuższe, ponieważ muszą odzwierciedlać krawędzie biegnące w obu kierunkach.
|
Listy sąsiedztwa są efektywnym pamięciowo sposobem reprezentacji grafu w pamięci komputera, ponieważ zajmują pamięć rzędu O(m), gdzie m oznacza liczbę krawędzi grafu. Listy sąsiedztwa pozwalają w prosty sposób reprezentować pętle oraz krawędzie wielokrotne, co sprawia, że są bardzo chętnie stosowane w algorytmach grafowych.
Oto kilka podstawowych operacji na listach sąsiedztwa:
Uwaga:
Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
Program odczytuje definicję grafu skierowanego, tworzy tablicę list sąsiedztwa i wypisuje ją w czytelnej formie. W tablicy są wykorzystywane listy jednokierunkowe. |
Dane przykładowe (przekopiuj do schowka i wklej
do okna konsoli):
|
Pascal// Listy sąsiedztwa // Data: 18.07.2013 // (C)2013 mgr Jerzy Wałaszek //--------------------------- program inc_matrix; // Typy dla dynamicznej tablicy list sąsiedztwa type PSLel = ^SLel; SLel = record next : PSLel; v : integer; end; TList = array of PSLel; var n, m, i, v1, v2 : integer; A : TList; p, r : PSLel; begin // Czytamy liczbę wierzchołków i krawędzi read(n, m); // Tworzymy tablicę list sąsiedztwa SetLength(A, n); // Tablicę wypełniamy pustymi listami for i := 0 to n-1 do A[i] := nil; // Odczytujemy kolejne definicje krawędzi for i := 0 to m-1 do begin // Wierzchołek startowy i końcowy krawędzi read(v1, v2); // Tworzymy nowy element listy new(p); // Numerujemy go jako v2 p^.v := v2; // Dodajemy go na początek listy A[v1] p^.next := A[v1]; A[v1] := p; end; writeln; // Wypisujemy zawartość tablicy list sąsiedztwa for i := 0 to n-1 do begin write ('A[', i, '] ='); p := A[i]; while p <> nil do begin write(p^.v:3); p := p^.next; end; writeln; end; // Usuwamy tablicę list sąsiedztwa for i := 0 to n-1 do begin p := A[i]; while p <> nil do begin r := p; p := p^.next; dispose (r); end; end; SetLength(A, 0); writeln; end. |
// Listy sąsiedztwa // Data: 18.07.2013 // (C)2013 mgr Jerzy Wałaszek //--------------------------- #include <iostream> #include <iomanip> using namespace std; // Typy dla dynamicznej tablicy list sąsiedztwa struct SLel { SLel * next; int v; }; int main() { int n, m, i, v1, v2; SLel ** A; SLel *p, *r; // Czytamy liczbę wierzchołków i krawędzi cin >> n >> m; // Tworzymy tablicę list sąsiedztwa A = new SLel * [n]; // Tablicę wypełniamy pustymi listami for(i = 0; i < n; i++) A[i] = nullptr; // Odczytujemy kolejne definicje krawędzi for(i = 0; i < m; i++) { // Wierzchołek startowy i końcowy krawędzi cin >> v1 >> v2; // Tworzymy nowy element p = new SLel; // Numerujemy go jako v2 p->v = v2; // Dodajemy go na początek listy A[v1] p->next = A[v1]; A[v1] = p; } cout << endl; // Wypisujemy zawartość tablicy list sąsiedztwa for(i = 0; i < n; i++) { cout << "A[" << i << "] ="; p = A[i]; while(p) { cout << setw(3) << p->v; p = p->next; } cout << endl; } // Usuwamy tablicę list sąsiedztwa for(i = 0; i < n; i++) { p = A[i]; while(p) { r = p; p = p->next; delete r; } } delete [] A; cout << endl; return 0; } |
Basic' Listy sąsiedztwa ' Data: 18.07.2013 ' (C)2013 mgr Jerzy Wałaszek '--------------------------- ' Typy dla dynamicznej tablicy ' list sąsiedztwa Type SLel next As SLel Ptr v As Integer End Type Dim As Integer n, m, i, v1, v2 Dim As SLel Ptr Ptr A Dim As SLel Ptr p, r Open Cons For Input As #1 ' Czytamy liczbę wierzchołków i krawędzi Input #1, n, m ' Tworzymy tablicę list sąsiedztwa A = new SLel Ptr [n] ' Tablicę wypełniamy pustymi listami For i = 0 To n-1 A[i] = 0 Next ' Odczytujemy kolejne definicje krawędzi For i = 0 To m -1 ' Wierzchołek startowy i końcowy krawędzi Input #1, v1, v2 ' Tworzymy nowy element p = new SLel ' Numerujemy go jako v2 p->v = v2 ' Dodajemy go na początek listy A [v1] p->next = A[v1] A[v1] = p Next Close #1 Print ' Wypisujemy zawartość ' tablicy list sąsiedztwa For i = 0 To n-1 Print Using "A[&] =";i; p = A[i] While p Print Using "###";p->v; p = p->Next Wend Print Next ' Usuwamy tablicę list sąsiedztwa For i = 0 To n-1 p = A[i] While p r = p p = p->Next Delete r Wend Next Delete [] A Print End |
Python
(dodatek)# Listy sąsiedztwa # Data: 25.11.2024 # (C)2024 mgr Jerzy Wałaszek #--------------------------- # Klasa elementu list sąsiedztwa class SLel: def __init__(self): self.next = None self.v = 0 # Czytamy liczbę wierzchołków i krawędzi x = input().split() n = int(x[0]) m = int(x[1]) # Tworzymy tablicę list sąsiedztwa a = [[]] * n # Odczytujemy kolejne definicje krawędzi for i in range(m): # Wierzchołek startowy i końcowy krawędzi x = input().split() v1 = int(x[0]) v2 = int(x[1]) # Tworzymy nowy element p = SLel() # Numerujemy go jako v2 p.v = v2 # Dodajemy go na początek listy A[v1] p.next = a[v1] a[v1] = p print() # Wypisujemy zawartość tablicy list sąsiedztwa for i in range(n): print("A[",i,"] =", sep="", end="") p = a[i] while p: print("%3d" % p.v, end="") p = p.next print() # Usuwamy tablicę list sąsiedztwa del a print() |
Wynik: |
6 8 0 1 1 2 2 2 1 3 3 1 2 4 4 0 4 3 A[0] = 1 A[1] = 3 2 A[2] = 4 2 A[3] = 1 A[4] = 3 0 A[5] = |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2024 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.