[알고리즘/C++] 그래프 순회 - 너비 우선 탐색(BFS)
2023. 8. 3. 22:28ㆍAlgorithm
깊이 우선 탐색 이외에도 너비 우선 탐색(BFS)라는 기법이 있다.
BFS는 노드를 순회할 때 리프 노드까지 먼저 가는 것이 아니라 같은 레벨(level)에 있는 노드를 먼저 순회하고
그 다음 레벨에 있는 노드를 순회하는 순서로 그래프를 순회한다.
void bfs(vector<vector<pair<int, int>>> adj, vector<bool>& visited, int start) {
visited[start] = true;
queue<int> q;
q.push(start);
while (!q.empty()) {
int now = q.front();
q.pop();
cout << now << "!!\n";
for (int i = 0; i < adj[now].size(); i++) {
if (visited[adj[now][i].first]) {
continue;
}
visited[adj[now][i].first] = true;
q.push(adj[now][i].first);
}
}
}
재귀 함수로 간단히 구현이 가능한 깊이 우선 탐색과는 달리, 너비 우선 탐색은 재귀 없이 구현해야하기 때문에
그 방법이 더 복잡한데, 그 메커니즘에 대해서 알아보자.
visited[start] = true;
queue<int> q;
q.push(start);
BFS도 DFS와 마찬가지로 visited 함수가 필요한데, 한번 방문한 노드를 다시 방문하지 않기 위함이다.
BFS는 레벨 순으로 내려가면서 노드를 순회하는데 visited가 필요한가? 라고 물을 수 있지만
'사이클이 있는 그래프'인 경우, visited를 사용하지 않는다면 BFS에서 무한 루프에 빠질 수 있다.
그리고 큐(queue) 자료구조를 사용하는데, 먼저 접한 레벨의 노드들을 먼저 다 순회해야하기 때문에
선입선출(FIFO) 구조인 큐를 사용하는 것이 적절하다.
while (!q.empty()) {
int now = q.front();
q.pop();
cout << now << "!!\n";
for (int i = 0; i < adj[now].size(); i++) {
if (visited[adj[now][i].first]) {
continue;
}
visited[adj[now][i].first] = true;
q.push(adj[now][i].first);
}
}
그리고 큐의 값들을 하나씩 pop하면서 노드를 순회한다.
현재 순회중인 노드의 자식 노드들을 살펴보면서 나중에 아래 레벨에 도달했을 때 순회하기 위해 큐에 push해준다.
자식 노드들을 큐에 push하면서 visited 처리해준다.
vector<vector<pair<int, int>>> adj;
initTree(adj);
vector<bool> visited(adj.size(), false);
bfs(adj, visited, 1);
1
2
3
4
5
6
7
8
9
10
11
'Algorithm' 카테고리의 다른 글
[알고리즘/C++] 다익스트라 알고리즘(Dijkstra's Algorithm) (0) | 2023.08.03 |
---|---|
[알고리즘/C++] 최단 경로 찾기 - 벨만-포드 알고리즘(Bellman-Ford) (0) | 2023.08.03 |
[알고리즘/C++] 그래프 순회 - 깊이 우선 탐색(DFS) (0) | 2023.08.03 |
[알고리즘/C++] 동적 계획법 - 엘리베이터 운행횟수 (0) | 2023.07.29 |
[알고리즘/C++] Knapsack problem(배낭 문제) (0) | 2023.07.29 |