루트 노드(혹은 임의의 다른 노드)에서부터 시작하여 인접한 노드를 먼저 탐색해 나가는 방법입니다.
또한 BFS는 그래프에서 최단 경로를 찾는 정점 기반 알고리즘으로 유명합니다.
특징은 다음과 같습니다.
시작 정점으로부터 가까운 정점을 먼저 방문하고 멀리 떨어져 있는 정점을 나중에 방문하는 순회 방법이다.
즉, 깊이(deep)탐색하기 전에 넓게(wide) 탐색하는 것이다.
사용하는 경우: 두 노드 사이의 최단 경로 혹은 임의의 경로를 찾고 싶을 때 이 방법을 선택한다.
예를 들어, 지구상의 존재하는 모든 인관관계를 표현한 후 철수와 영희 사이에 존재하는 경로를 찾는 경우
깊이 우선 탐색(DFS)의 경우 - 모든 인간 관계를 다 살펴봐야 할 수도 있다.
너비 우선 탐색(BFS)의 경우- 철수와 가까운 관계부터 탐색한다.
너비 우선 탐색(BFS)이 깊이 우선 탐색(DFS)보다 더 복잡하다.
4. BFS의 특징
BFS의 특징 몇 가지를 더 자세히 살펴 보도록 하겠습니다.
직관적이지 않다.
BFS는 시작 노드를 기준으로 거리에 따라 단계별로 탐색하는 것이기 때문에 다소 오해가 발생할 수 있다.
BFS는 재귀적으로 동작하지 않는다.(DFS와 달리)
이후 구현에서 다룰 것이지만 반드시 그래프를 탐색하면서 어떤 노드를 방문했었는 지의 여부를 검사해야한다. (구현에서 visited 변수)
무한루프에 빠질 위험이 있기 때문
BFS는 대기순서에 따라 반복적인 방문을 해야하기 때문에 큐(Queue)를 사용하여 구현한다.
다시말해서 선입선출(FIFO)의 원칙으로 탐색
다양한 방법이 있지만 queue의 형태로 구현하는 것이 바람직함
먼저 들어온 데이터 들을 먼저 탐색하는 방식이기 때문.
이후에 배울 'Prim', 'Dijkstra' Algorithms과 비슷하다.
5. BFS의 과정
그림을 통해 알아보도록 하겠습니다.
시작 노드 A를 방문한다.
시작 정점을 방문하여 방문 표시(visited, 초록색 표시)한 후 해당 노드를 enqueue한다.
큐에서 첫번째 정점을 제거하고 제거된 정점과 인접한 정점에 대하여 방문하지 않은 정점을 방문한다.
큐에서 꺼낸 노드를 방문한다.
이 노드와 인접하는 노드들을 모두 방문(enqueue)한다.
인접한 노드가 없으면 큐의 맨 앞(peek)에서 노드를 꺼낸다(dequeue).
큐가 소진될 때까지 위 과정을 반복한다.
큐에서 데이터가 빠짐(dequeue)과 동시에 해당 데이터는 초록색이 되고 이와 인접한 노드는 노란색이 되면서 방문(enqueue)을 한 상태가 되고 큐에서 순서대로 데이터를 빼면서(초록색으로 만들면서) 인접 노드들이 큐에 삽입되는(노란색이 되는, 큐에 진입) 과정을 반복하는 것이다. (모든 노드가 초록색이 될 때까지, 즉 큐가 빌 때까지 반복한다.)
방문순서 : A-B-C-D-E-F-G-H
6. BFS 탐색 구현(Java)
package graph;
import java.util.*;
publicclassGraphAlgorithms{
publicstatic List<Integer> bfs(IGraph iGraph, int from){
List<Integer> result = newArrayList<>();
Set<Integer> visited = newHashSet<>();
Queue<Integer> queue = newLinkedList<>();
queue.add(from);
visited.add(from);
while (!queue.isEmpty()) {
Integernext= queue.poll();
result.add(next);
for (Integer n : iGraph.getNodes(next)) {
if(!visited.contatins(n)) {
queue.add(n);
visited.add(n);
}
}
}
return result;
}
}
Input parameter: 지난 시간 구현한 그래프(iGraph), 시작 노드(from)
Return: 방문한 노드를 순서대로 저장한 리스트
과정:
처음에 시작할 때는 시작 노드(from)부터 시작한다.
queue에 시작노드를 삽입하고 방문하였기 때문에 visited에도 넣어준다.
큐가 비어있을 때까지 다음을 반복한다.
next변수에 큐의 데이터를 하나씩 빼온다.
해당 데이터를 result 변수에 넣어주고
next와 인접한 노드들이 0개, 1개 혹은 여러개 일 것이기 때문에 for문으로 이를 하나씩 순회하여 만약 방문하지 않았다면 (visited에 존재하지 않는다면) queue에 삽입하고 visited에도 삽입한다.
큐가 모두 비었다면 어떤 순서로 탐색을 진행했는 지의 결과인 result를 반환하여 마무리한다.
너비 우선 탐색 과정깊이 우선 탐색 과정
7. BFS 사용 예시 - 최단 경로 문제
너비 우선 탐색(BFS)는 퍼즐 게임 등을 해결할 때 많이 쓰이는 알고리즘이다. 또한 다익스트라 알고리즘에도 사용되며 이에 대한 포스팅은 다음을 참고하세요.