Depth First Search (DFS)

by Jerry Sky

Przeszukiwanie w głąb



DFS grafu nieskierowanego – procedura pozwalająca na eksplorację wszystkich wierzchołków grafu. DFS pozwala odpowiedzieć na pytanie do których wierzchołków grafu można dojść startując z zadanego wierzchołka.

explore(G,v)(G,v)

Reprezentujemy graf przy pomocy listy sąsiedztwa. Reprezentacja ta pozwala tylko na znajdowanie sąsiadów wierzchołków grafów. Przyjrzyjmy się procedurze explore(G,v)(G,v), która pozwala znaleźć wszystkie wierzchołki grafu G=(V,E)G = (V,E) dostępne z wierzchołka vVv \in V.

explore(G,v)(G,v):

  1. visited(v)=True\mathrm{visited}(v) = \mathrm{True}
  2. previsit(v)(v)
  3. for each {v,u}E\{v,u\} \in E:
    1. if not visited(u)\mathrm{visited}(u):
      1. explore(u)(u)
  4. postvisit(v)(v)

Procedur previsit oraz postvisit są opcjonalne i pozwalają na wykonanie operacji w momencie odpowiednio pierwszego odwiedzenia wierzchołka i opuszczenia wierzchołka.

visited jest flagą, która zostanie ustawiona na true dla wszystkich wierzchołków do których można dojść z wierzchołka startowego.

Szkic dowodu poprawności procedury explore(G,v)(G,v) można wykonać nie wprost:

Przykład explore:

maze

result

DFS(G)(G)

  1. for all vVv \in V:
    1. visited(v)=False(v) = \mathrm{False}
  2. for all vVv \in V:
    1. if not visited(v)(v):
      1. explore(v)(v)

Złożoność obliczeniowa:

Pierwszy krok (pętla) sumarycznie dla całego grafu GG będzie miał złożoność O(V)O(|V|). Drugi krok w każdym wierzchołku ma złożoność obliczeniową zależną od stopnia tego wierzchołka.
Jeśli spojrzymy na to z perspektywy całego grafu to widzimy, że drugi krok przechodzi po każdej krawędzi w grafie dwa razy (dla {u,v}E\{u,v\} \in E raz dla explore(u)(u), drugi raz dla explore(v)(v)).

Zatem złożoność drugiego kroku w całym grafie to O(E)O(|E|). W sumie złożoność obliczeniowa DFS wynosi O(V+E)O(|V| + |E|), czyli liniowo w stosunku do wielkości grafu.

Zastosowanie - spójność grafu

Dodajemy do każdego wierzchołka parametr component_number, zainicjować zmienną cc = 0 na początku procedury DFS, zdefiniować procedurę

previsit(v)(v):

  1. v.v.component_number = cc

oraz zwiększać zmienną cc o 11 za każdym razem gdy w procedurze DFS jest procedura explore. Po wykonaniu tak zmodyfikowanego DFSa w zmiennych component_number każdego wierzchołka mamy zapisane, do której komponent należy dany wierzchołek, a zmienna cc zawiera liczbę komponent.

More