Przeszukiwanie grafu w głąb (DFS) jest używane w badaniu spójności grafu (prostego oraz skierowanego). Ponadto algorytm ten jest wykorzystywany w wielu innych algorytmach np. sortowaniu topologicznym. W tym artykule zostanie wyjaśniona podstawowa implementacja tego algorytmu.
Przeszukiwanie w głąb (DFS) jest to algorytm rekurencyjny. Do działania potrzebna jest tablica o tylu elementach ile jest węzłów w przekazanym grafie, gdzie można przechować informację czy dany element został odwiedzony oraz jaki jest jego poprzednik. Działanie algorytmu jest następujące: przygotuj tablicę, a następnie dla każdego nieodwiedzonego węzła odwiedź go. Odwiedzenie węzła polega na przypisaniu temu węzłowi, że został odwiedzony, a następnie należy odwiedzić wszystkich jego sąsiadów.
Istnieje możliwość zastosowania algorytmu DFS dla dowolnego wierzchołka. Należy pamiętać, że z wierzchołka 1 i 2 uzyska się dwa różne wyniki. Jeśli algorytm ma rozpocząć przeszukiwanie od innego wierzchołka niż pierwszego w grafie to należy wpierw odwiedzić określony wierzchołek startowy zanim zacznie się przchodzić wszystkie po kolei.
Poniższy przykład pokaże działanie algorytmu DFS dla poniższego grafu:
Punktem początkowym jest zaznaczony punkt A. W tabeli została przedstawiona aktualna kolejka oraz właściwości poszczególnych obiektów:
Węzeł | A | B | C | D | E | F | G | H | Komentarz |
---|---|---|---|---|---|---|---|---|---|
A | 0, ☑ | ∞, ☐ | ∞, ☐ | ∞, ☐ | ∞, ☐ | ∞, ☐ | ∞, ☐ | ∞, ☐ | [A] Przeglądamy sąsiadów A, czyli B, C, D |
.B | 0, ☑ | A, ☑ | A, ☐ | A, ☐ | ∞, ☐ | ∞, ☐ | ∞, ☐ | ∞, ☐ | [B] Przeglądamy sąsiadów B: E |
..E | 0, ☑ | A, ☑ | A, ☐ | A, ☐ | B, ☐ | ∞, ☐ | ∞, ☐ | ∞, ☐ | [B] Przeglądamy sąsiadów B: E |
..E | 0, ☑ | A, ☑ | A, ☐ | A, ☐ | B, ☑ | ∞, ☐ | ∞, ☐ | ∞, ☐ | [E] Brak sąsiadów, powrót do B |
.B | 0, ☑ | A, ☑ | A, ☐ | A, ☐ | B, ☑ | ∞, ☐ | ∞, ☐ | ∞, ☐ | [B] Brak sąsiadów, powrót do A |
A | 0, ☑ | A, ☑ | A, ☐ | A, ☐ | B, ☑ | ∞, ☐ | ∞, ☐ | ∞, ☐ | [A] Przeglądanie kolejnego sąsiada: C |
.C | 0, ☑ | A, ☑ | A, ☑ | A, ☐ | B, ☑ | ∞, ☐ | ∞, ☐ | ∞, ☐ | [C] Brak sąsiadów, powrót do A |
A | 0, ☑ | A, ☑ | A, ☑ | A, ☐ | B, ☑ | ∞, ☐ | ∞, ☐ | ∞, ☐ | [A] Przeglądanie ostatniego sąsiada: D |
.D | 0, ☑ | A, ☑ | A, ☑ | A, ☑ | B, ☑ | D, ☐ | ∞, ☐ | D, ☐ | [D] Przeglądanie sąsiadów D: F, H |
..F | 0, ☑ | A, ☑ | A, ☑ | A, ☑ | B, ☑ | D, ☑ | ∞, ☐ | D, ☐ | [F] Brak sąsiadów, powrót do D |
.D | 0, ☑ | A, ☑ | A, ☑ | A, ☑ | B, ☑ | D, ☑ | ∞, ☐ | D, ☐ | [D] Przeglądanie kolejnego sąsiada H |
..H | 0, ☑ | A, ☑ | A, ☑ | A, ☑ | B, ☑ | D, ☑ | H, ☐ | D, ☑ | [H] Przeglądanie sąsiada G |
...G | 0, ☑ | A, ☑ | A, ☑ | A, ☑ | B, ☑ | D, ☑ | H, ☑ | D, ☑ | [G] Brak nieodwiedzonych sąsiadów, powrót do H |
..H | 0, ☑ | A, ☑ | A, ☑ | A, ☑ | B, ☑ | D, ☑ | H, ☑ | D, ☑ | [G] Brak nieodwiedzonych sąsiadów, powrót do D |
.D | 0, ☑ | A, ☑ | A, ☑ | A, ☑ | B, ☑ | D, ☑ | H, ☑ | D, ☑ | [D] Brak nieodwiedzonych sąsiadów, powrót do A |
A | 0, ☑ | A, ☑ | A, ☑ | A, ☑ | B, ☑ | D, ☑ | H, ☑ | D, ☑ | [A] Brak nieodwiedzonych sąsiadów, koniec algorytmu |
Algorytm kończy działanie, ponieważ wierzchołek A nie ma już więcej sąsiadów, a wszystkie pozostałe wierzchołki zostały już odwiedzone. Z tego można wywnioskować, że graf jest spójny, ponieważ z wierzchołka A zostały osiągnięte wszystkie inne wierzchołki. Na koniec została uzyskana następująca tablica:
Węzeł | A | B | C | D | E | F | G | H |
---|---|---|---|---|---|---|---|---|
Poprzednik | 0 | A | A | A | B | D | H | D |
Na jej podstawie można prześledzić działanie algorytmu. Należy pamiętać, że znalezione tutaj drogi z pewnego wierzchołka do innego wcale nie muszą być najkrótsze. Przy takim zadaniu należy zastosować wtedy algorytm BFS.
Algorytm zostanie podzielony na dwie części: funkcję DFS(), która przygotuje tablicę i zainicjuje odwiedzanie oraz funkcję odwiedzWezel(), która będzie rekurencyjnie przechodziła po grafie dalej.
Poniżej została przedstawiona funkcja DFS(), która przyjmuje dwa argumenty: macierz - macierz sąsiedztwa grafu oraz start - wierzchołek początkowy od którego ma zostać rozpoczęte przeszukiwanie.
(2.) Inicjalizacja tablicy i (3. - 4.) jej początkowe ustawienie. Następnie (5.) odwiedź węzeł początkowy, a potem (6. - 8.) pozostałe, nieodwiedzone wierzchołki alfabetycznie. Na koniec (9.) zwróć obliczoną tablice.
Odwiedzenie wierzchołka polega na przypisaniu, że został odwiedzony (bez tego rekurencja byłaby nieskończona), a następnie odwiedza wszystkich nieodwiedzonych sąsiadów wierzchołka przypisując im, że poprzednikiem jest aktualnie odwiedzony wierzchołek.
(2.) Zaznacz, że wierzchołek został odwiedzony i (3.) wyszukaj sąsiadów, którzy (4.) nie zostali odwiedzeni, a następnie (5.) zaktualizuj ich poprzednika oraz (6.) odwiedź je.
Działanie napisanej funkcji można sprawdzić poniższym fragmentem kodu, który wczyta od użytkownika dane, a następnie wypisze wynik.