(학교 수업 자료를 참고하여 작성하였습니다.)
DFS, BFS는 탐색 알고리즘으로 브루트포스에 포함된다. 주로 그래프와 트리를 순회할 때 사용되고, 탐색 방법과 목적에는 약간의 차이가 있다. 그치만 코딩테스트 문제들에서 DFS, BFS를 따지지 않고 탐색만 하는 것으로 해결되는 경우도 많다고 한다.
- 그래프: 연결되어 있는 객체 간의 관계를 표현하는 자료구조
- 트리: 그래프의 한 종류로, 사이클이 없는 N개 노드, (N-1)개 간선을 가진 연결된 그래프
그래프는 인접 행렬(O(N^2)), 인접 리스트(O(N+E)) 형태로 구현한다.
깊이 우선 탐색, DFS
- DFS: Depth-First Search의 약자로 깊이 우선 탐색을 말한다
- 한 방향으로 갈 수 있을 때까지 가다가 더 이상 갈 수 없게 되면 가장 가까운 갈림길로 돌아와서 다른 방향으로 다시 탐색한다
= 방문하지 않은 인접 노드가 없을 때까지 탐색 진행 - 되돌아가기 위해서는 스택이 필요
⇒ 주로 재귀함수를 호출하여 묵시적으로 스택 이용
- 적용
- 시작 노드로부터 먼 solution이 있을 때 더 suitable
- 경로가 존재하는지 여부를 파악하는 문제
- 최단 경로를 찾는 것은 보장하지 않음
- 지나온 경로의 특징을 저장하고 추적하는 문제에 적합
- ex. 특정 노드 포함 경로 찾기, 가중치 합이 특정 조건을 만족하는 경로 찾기
- 탐색 방법
1. 시작 노드를 호출하여 방문 배열에 표시한다.
2. 그의 방문하지 않은 인접 노드를 호출하는 것으로 반복한다.
3. 내부 함수가 종료되면 호출한 곳으로 다시 돌아간다.
- 코드
구현 시 인접 행렬 혹은 인접 리스트(ex. ArrayList<ArrayList<Integer>> A 배열)와 방문 배열(ex. boolean visited 배열)을 필요로 한다.
static void dfs(int node) {
visited[node] = true; // 해당 노드를 방문했다고 표시
for(int i: A[node]) { // 해당 노드의 인접 노드 탐색
if(!visited[i]) { // 방문하지 않은 인접 노드가 있다면
dfs(i); // 재귀 함수 호출로 깊이 탐색 진행
}
}
}
너비 우선 탐색, BFS
- BFS: Breadth-First Seach의 약자로 너비 우선 탐색을 말한다
- 시작 정점으로부터 가까운 정점을 먼저 방문하고 멀리 떨어져 있는 정점을 나중에 방문하는 순회 방법
- 큐를 사용하여 구현
- 큐 구현 시 LinkedList를 사용하는 것보다 ArrayDeque를 사용하는 게 성능상 우수하다
* ArrayDeque
"This class is likely to be faster than Stack when used as a stack, and faster than LinkedList when used as a queue. " (cf. https://docs.oracle.com/javase/8/docs/api/)
Java Platform SE 8
docs.oracle.com
- 적용
- 시작 노드로부터 인접한 정점들을 먼저 탐색할 때 더 suitable
- 출발지로부터 인접한 모든 가능한 경로 탐색, 한 층씩 너비를 늘려가며 목적지에 도달하는 경로 찾을 수 있음
- 이분 그래프, 최단 경로
- 모든 경로의 깊이(depth)나 이동 횟수(count) 계산하고 비교
- ex. 미로에서의 최단 경로 구하기, 특정 거리의 노드 찾기
- 탐색 방법
0. 큐를 생성한다.
1. 시작 노드를 큐에 삽입하고 방문 배열에 표시한다.
2. 큐가 빌 때까지 요소를 꺼낸다.
2.1. 큐의 맨앞 요소를 꺼낸 후, 그의 방문하지 않은 인접 노드가 있다면 큐에 삽입한다. (큐에 이미 삽입된 노드는 추가하지 않는다.)
2.2. 방문 배열에 해당 인접 노드를 표시한다.
- 코드
구현 시 인접 행렬 혹은 인접 리스트(ex. ArrayList<ArrayList<Integer>> A 배열)와 방문 배열(ex. boolean visited 배열)을 필요로 한다.
(cf. 이중 배열 https://stackoverflow.com/questions/24796273/incompatible-types-list-of-list-and-arraylist-of-arraylist)
static void bfs(int node) {
Queue<Integer> queue = new ArrayDeque<>(); // ArrayDeque로 구현
queue.offer(node); // 시작 노드 삽입
visited[node] = true; // 방문 배열에 표시
while(!queue.isEmpty()) { // 큐가 빌 때까지 진행
int num = queue.poll(); // 맨 앞 요소 꺼내어
for(int i: A[num]) { // 해당 노드의 인접 노드 탐색
if(!visited[i]) { // 방문하지 않은 노드가 있다면
queue.offer(node); // 큐에 삽입함
visited[node] = true;
}
}
}
}
cf. https://www.geeksforgeeks.org/difference-between-bfs-and-dfs/
Difference between BFS and DFS - GeeksforGeeks
A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.
www.geeksforgeeks.org
https://www.acmicpc.net/source/77026419
https://www.acmicpc.net/source/56402164
'문제 및 이론 정리 > Algorithm' 카테고리의 다른 글
[알고리즘] 그래프 최단거리 - 다익스트라(Dijkstra) 알고리즘 (1) | 2024.12.07 |
---|---|
[알고리즘] 병합 정렬(MergeSort) 핵심 아이디어 (1) | 2024.09.28 |
[알고리즘] 정렬 알고리즘 - QuickSort(퀵 정렬) (2) | 2024.09.03 |
[알고리즘] 조합과 동적 계획법 (dynamic programming) (0) | 2024.08.20 |
[알고리즘] 등차수열의 합과 이진 탐색(Binary Search) (0) | 2024.08.18 |