1. DFS 알고리즘이란
- 그래프 탐색 알고리즘의 한 종류
- 그래프 탐색이란 한 정점으로부터 시작하여 다른 정점을 차례대로 모두 한번씩 방문하는 것
- DFS는 Depth First Search의 약자로서, 임의의 정점에서 시작하여 다른 분기로 넘어가기 전에 해당 분기를 완전히 탐색하는 방법이다.
2. DFS의 특징
- 모든 노드를 방문하고자 할 때 이 방법을 선택함
- 넓게 탐색하기 전에 깊이 탐색함
- 자기 자신을 호출하는 순환 알고리즘의 형태를 가짐
- 전위 순회를 포함한 다른 형태의 트리 순회는 모두 DFS의 한 종류임
- 어떤 노드를 방문했는지 여부를 반드기 검사해야 무한 루프에 빠지는 것을 방지할 수 있음
- 백트래킹에 사용됨
3. 장점
- BFS(너비 우선 탐색)보다 구현이 간단함
- 현재 경로 상 노드만 기억하면 되기 때문에 저장 공간이 적게 요구됨
- 목표값이 깊은 곳에 있다면 빠르게 찾아낼 수 있음
4. 단점
- BFS에 비해 탐색 속도가 느림
- 해가 존재하지 않는 경우 계속 탐색을 진행할 가능성이 있음, 임의의 종결 조건을 선언하여 탐색을 종료할 필요가 있음
- 해가 도출되면 탐색을 종료하므로 최적의 해가 아닐 가능성이 있음
5. DFS를 사용해야 하는 문제
1) 경로의 특징을 저장해야 하는 문제
예를 들면 각 정점에 숫자가 적혀있고 a부터 b까지 가는 경로를 구하는데 경로에 같은 숫자가 있으면 안 된다는 문제 등, 각각의 경로마다 특징을 저장해둬야 할 때는 DFS를 사용(BFS는 경로의 특징을 가지지 못함)
2) 그래프의 크기가 정말 클 때
※ 모든 정점을 방문하는 것이 중요한 문제의 경우 DFS, BFS 두 가지 방법 중 어느 것을 사용해도 상관없음
6. 구현
1) 재귀로 구현
graph = {1: [2, 3, 4], 2: [5, 6], 3: [8],
4: [8, 9], 5: [7], 6: [],
7: [3], 8: [], 9: []}
def dfs_recursive(node, visited_path=[]):
visited_path.append(node)
for v in graph[node]:
if v not in visited_path:
recursive_dfs(v, visited_path)
return visited_path
print(f'dfs_recursive path: {dfs_recursive(1)}')
2) 스택으로 구현
def dfs_stack(start_node):
visited_path = []
stack = [start_node]
while stack:
parent = stack.pop()
if parent not in visited_path:
visited_path.append(parent)
for child in graph[parent]:
stack.append(child)
return visited_path
print(f'dfs_stack path: {dfs_stack(1)}')
인접 정점을 한번에 stack에 추가한다는 점에서 BFS처럼 보일 수 있으나 DFS가 맞다. 후입된 정점을 pop으로 선출하기 때문이다.
'자료구조와 알고리즘 > 알고리즘' 카테고리의 다른 글
[알고리즘] 다익스트라(Dijkstra) 알고리즘 (0) | 2022.04.03 |
---|---|
[알고리즘] BFS(너비 우선 탐색) (0) | 2022.03.14 |