깊이 우선 탐색(DFS)과 너비 우선 탐색(BFS)는 두가지 모두 그래프를 탐색하는 방법입니다.
그래프란, 정점(node)와 그 정점을 연결하는 간선(edge)로 이루어진 자료 구조의 일종. G = (V, E)
그래프를 탐색한다는 것은 하나의 정점으로부터 시작하여 차례대로 모든 정점들을 한 번씩 방문하는 것.Ex) 특정 도시에서 다른 도시로 갈 수 있는지 없는지, 전자 회로에서 특정 단자와 단자가 서로 연결되어 있는지
-> 그래프 중 방향성이 있는 비순환 그래프 : 트리
최대한 깊이 내려간 뒤, 더이상 깊이 갈 곳이 없을 경우 옆으로 이동.
ex) 미로찾기
-> 최대한 한 방향으로 갈 수 있을 때까지 가다가 막다른 길이면 다시 가장 가까운 갈림길로 돌아와 그 갈림길부터 다시 다른 방향으로 탐색 진행.
최대한 넓게 이동한 다음, 더 이상 갈 수 없을 때 아래로 이동.
ex) 지구 상에 존재하는 모든 친구 관계를 그래프로 표현한 후 Sam과 Eddie 사이에 존재하는 경로를 찾는 경우
-> 깊이 우선 탐색 : 모든 친구 관계를 다 살펴봐야 할지도 모름.
-> 너비 우선 탐색 : Sam과 가까운 관계부터 탐색.
깊이 우선 탐색(DFS) | 너비 우선 탐색(BFS) |
---|---|
현재 정점에서 갈 수 있는 점들까지 들어가면서 탐색 | 현재 정점에 연결된 가까운 점들부터 탐색 |
스택 또는 재귀함수로 구현 | 큐로 구현 |
- 인접 행렬 : O(N^2)
- 인접 리스트 : O(N+E)
(N : 노드, E : 간선)
- 일반적으로 E(간선)의 크기가 N^2에 비해 상대적으로 적기 때문에 인접 리스트 방식이 효율적.
- 인접 행렬 : 정점의 개수 N만큼 도는 2중 for문을 돌려 두 정점 간에 간선이 존재하는지 확인.
- 인접 리스트 : 존재하는 간선의 정보만 저장되어 인접 행렬에서 사용한 2중 for문 필요하지 않음.
다음 노드가 방문하였는지 확인할 때 간선의 개수인 E의 두 배만큼의 시간이 걸리고,
각 노드를 방문할 때 정점의 개수인 N만큼 걸림.
모든 정점은 3가지 상태를 거침
1. 아직 발견되지 않은 상태 (!check[i])
2. 발견되었지만 방문하지 않은 상태
3. 방문된 상태 (check[i])
// [재귀적 dfs]
// 인접 행렬 dfs
void dfs(int x) {
check[x] = true;
for(int i = 0; i < V ; i++) {
if(graph[x][i] == 1 && !check[i]) { // 간선으로 이어져 있고 방문 안한 곳
dfs(i);
}
}
}
// 인접 리스트 dfs
void dfs(List[] list, int x) {
check[x] = true;
for(int i = 0; i < list[x].size(); i++) {
int next = (int) list[x].get(i);
if(!check[next])
dfs(next);
}
}
// [큐로 bfs 구현]
// 인접 행렬 bfs
void bfs(int v, int start) {
Queue<Integer> q = new LinkedList<>();
boolean check[] = new boolean[v];
check[start] = true;
q.add(start);
while(!q.isEmpty()) {
int now = q.poll();
for(int i = 0; i < v; i++) {
if(graph[now][i] == 1 && !check[i]) { // 간선으로 이어져 있고 방문 안한 곳
check[i] = true;
q.add(i); // 방문 예정
}
}
}
}
// 인접 리스트 bfs
void bfs(List[] list, int v, int start) {
Queue<Integer> q = new LinkedList<>();
boolean check[] = new boolean[v+1];
check[start] = true;
q.add(start);
while(!q.empty()) {
int now = q.poll();
for(int i = 0; i < list[now].size(); i++){
int next = (int) list[now].get(i);
if(!check[next]){
check[next] = true;
q.add(next); // 방문 예정
}
}
}
}
1) 그래프의 모든 정점을 방문하는 것이 주요한 문제
2) 경로의 특징을 저장해둬야 하는 문제
3) 최단거리 구해야 하는 문제
그 외
참고
https://devuna.tistory.com/32
https://loosie.tistory.com/151