본문 바로가기

프로그래밍/알고리즘

그래프에서의 BFS

Graph Traversal


그래프 순회

- 순회 (traversal)

그래프의 모든 노드들을 방문하는 일을 말한다.

- 순회를 하는 두 가지 방법

BFS (Breadth-First Search, 너비 우선 순회)

DFS (Depth-First Search, 깊이 우선 순회)


너비 우선 순회 (BFS)

- BFS 알고리즘은 아래와 같은 순서로 노드들을 방문하게 된다.

$L_0$ = {s} (s : 출발 노드)

$L_1$ = $L_0$의 모든 이웃 노드들

$L_2$ = $L_1$의 이웃들 중 $L_0$의 이웃에 속하지 않은 노드들

...

$L_i$ = $L_{i-1}$의 이웃들 중에 $L_{i-2}$에 속하지 않는 노드들

*level order은 BFS의 이진 트리 버전이다.

큐를 이용한 너비 우선 순회

1) check the start node; // check는 이미 방문한 노드라는 것을 표시한다는 뜻이다.

2) insert the start node into the queue;

3) while queue is not empty

remove a node v from queue;

for each unchecked neighbor w of v

check and insert w into the queue;


BFS와 최단 경로에 대해

- s에서 $L_i$에 속한 노드까지 최단 경로의 길이는 i이다. (결로의 길이는 경로에 속한 엣지의 개수를 의미한다.)

- BFS를 진행하며 각 노드에 대한 최단 경로의 길이를 구할 수 있게 된다.

- 입력 : 방향 혹은 무방향 그래프 G = (V, E), 출발 노드 s ∈ V

- 출력 : 모든 노드인 v에 대하여

d[v] = s부터 v까지 최단 경로의 길이 (엣지의 개수)

π[v] = s부터 v까지 최단 경로 상에서 v의 직전 노드를 의미한다.


BFS 구현 코드

BFS (G, s) // G : 그래프, s : 출발 노드

Q <- ;

d[s] <- 0; // 최단 경로의 길이를 0으로 초기화

π[s] <- null; // predecessor를 null로 초기화

Enqueue (Q, s);

while Q ≠ 

u <- Dequeue (Q);

for each v adjacent to u // 보통은 모든 노드에 대해 d[v]를 -1로 초기화한 후 -1이면 미방문, 아니면 방문으로 판단.

if v is unvisited

mark v as visited;

d[s] <- d[u] + 1;

π[s] <- u; // u를 v의 predecessor로 설정한다.

Enqueue (Q, v);

- 개선

BFS (G, s)

Q <- ;

for each node u

d[u] <- -1;

π[u] <- null;

d[s] <- 0; π[s] <- null;

Enqueue (Q, s);

while Q ≠ ∅ // while문을 한 번 반복할 때마다 큐에서 하나를 꺼내기 때문에 최대 n번 반복한다.

u <- Dequeue (Q);

for each v adjacent to u // 인접리스트로 구현할 경우 for문은 각 노드 v에 대해 degree(v)번 돈다.

if d[v] == -1

d[v] <- d[u] + 1;

π[v] <- u;

Enqueue (Q, v); //unchecked 노드만 큐에 들어갈 수 있기에 어떤 노드들도 큐에 두 번 들어가지는 않는다.

-> 인접리스트로 구현할 때의 시간복잡도는 $\sum _{ v }{ degree(v) }$ = 2m이므로 O(n + m)의 시간 복잡도를 가진다.

- BFS를 이용하여 각 노드의 d와 π값을 계산한 결과 그래프


BFS 트리

- 각 노드 v와 π[v]를 연결하는 엣지들로 구성된 트리이다.

- BFS트리에서 s부터 v까지의 경로는 곧 s에서 v까지 가는 최단경로이다.

- 어떠한 엣지도 2개의 레이어를 건너가지 않는다.

(동일 레이어의 노드를 연력하거나 1개의 레이어를 건너간다.


BFS : 최단 경로 출력하기

PRINT-PATH (G, s, v)

if v == s

print s;

else if  π[v] == null

print "no path from s to v exists";

else

PRINT-PATH (G, s, π[v]);

print v;

- 그래프가 disconnected이거나 방향 그래프라면 BFS를 사용했을 때 모든 노드를 방문하지 않을 수 있다.

- 이 때는 BFS를 반복하여 모든 노드를 방문하게 한다.

BFS-ALL (G)

while there exists unvisited node v

BFS(G, v);

'프로그래밍 > 알고리즘' 카테고리의 다른 글

DAG와 위상 순서  (0) 2019.06.11
그래프에서의 DFS  (0) 2019.06.10
그래프의 개념과 표현  (0) 2019.06.10
해싱 (Hashing) (3)  (0) 2019.06.09
해싱 (Hashing) (2)  (0) 2019.06.09