어떤 한 그래프와 해당 그래프의 시작 정점이 주어졌을 때, 시작점에서 간선(Edge, E)을 타고 이동할 수 있는 정점(Vertex, V)들을 모두 찾아야 하는 문제
시작 정점으로부터 가까운 정점을 먼저 방문하고 멀리 떨어져 있는 정점은 나중에 순회한다. 깊이 우선 탐색(DFS)보다 좀 더 복잡하다.
기억할 것
- 방문한 노드는 체크한다.
- 방문된 노드는 큐에 삽입한다.
enqueue
dequeue
enqueue
큐(Queue)를 사용하여 구현한다.
pseudocode
search(Node root){
Queue queue = new Queue(); // 방문할 노드들을 저장하는 큐
root.marked = true; // 방문한 노드 체크
queue.enqueue(root); // 큐의 끝에 추가
// 큐가 다 없어질 때까지 계속한다.
while(!queue.isEmpty()){
Node r = queue.dequeue(); // 앞에 노드 추출
visit(r); // 추출한 노드 방문
// 큐에서 꺼낸 노드와 인접한 노드를 모두 차례로 방문
foreach(Node n in r.adjacent) {
// 인접한 노드가 방문되지 않은 상태라면
if(n.marked == false) {
n.marked = true; // 방문한 노드 체크
queue.enqueue(n); // 큐의 끝에 추가
}
}
}
}
Java
다음은 인접 행렬을 이용해서 풀이한 코드이다.
void bfs(int start, int[][] graph, boolean[] visited){
// BFS에 사용할 큐를 생성한다.
Queue<Integer> q = new LinkedList<Integer>();
// 큐에 BFS를 시작할 노드 번호를 넣는다.
q.offer(start);
// 시작노드는 방문표시
visited[start] = true;
// 큐가 빌 때까지 반복한다.
while(!q.isEmpty()) {
int nodexIndex = q.poll();
for(int i =0; i < graph[nodeIndex].length; i++){
int temp = graph[nodeIndex][o];
// 방문하지 않았으면 방문처리 후 방문할 큐에 넣는다.
if(!visited[temp]){
visited[temp] = true;
q.offer(temp);
}
}
}
}
시간 복잡도
- 인접리스트: O(N+E)
- 인접 행렬: O(N^2)
노드에서 다음 분기로 넘어가기 전에 해당 분기를 완벽하게 탐색한다.
구현 방법
- 순환 호출을 이용한다.
- 명시적인 스택을 사용하여, 방문한 정점들을 스택에 저장했다 다시 꺼내어 사용한다.
의사코드
void search(Node root) {
if (root == null) return;
// 1. root 노드 방문
visit(root);
root.visited = true; // 1-1. 방문한 노드를 표시
// 2. root 노드와 인접한 정점을 모두 방문
for each(Node n in root.adjacent) {
if (n.visited == false) { // 4. 방문하지 않은 정점을 찾는다.
search(n); // 3. root 노드와 인접한 정점을 시작 정점으로 DFS를 시작한다.
}
}
}
시간 복잡도
O(N+E)
O(N^2)
Reference
감사합니다! 😌