일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- fork()
- 추상화
- 스케줄링
- 기아 상태
- concurrency
- Oracle
- 동기화
- 스레드
- 세마포어
- 백준
- 우선순위
- 알고리즘
- 교착상태
- 페이지 대치
- PYTHON
- 부동소수점
- 프로세스
- 페이지 부재율
- 페이징
- mutex
- 트랩
- Algorithm
- 단편화
- mips
- BOJ
- 컴퓨터구조
- 가상 메모리
- 운영체제
- 인터럽트
- ALU
- Today
- Total
봉황대 in CS
[알고리즘] BFS와 DFS의 개념, 차이점과 구현(Python) 본문
[알고리즘] BFS와 DFS의 개념, 차이점과 구현(Python)
등 긁는 봉황대 2022. 7. 2. 22:11너비 우선 탐색 (Breadth-First Search, BFS)
인접한 노드를 먼저 탐색하는 방식 (매 단계에서 가능한 경우의 수들을 모두 확인하면서 탐색)
* 최대한 넓게 이동하여 더 이상 옆으로 갈 곳이 없을 경우 아래로 이동
1. Queue를 통해 구현
2. 최단 경로를 찾을 때 주로 사용
탐색 경로를 결과로 출력한다고 하면 BFS의 파이썬 구현 코드는 다음과 같다.
* 양방향 큐(deque) 사용
# N×N 2차원 배열
dy = (-1, 0, 1, 0)
dx = (0, 1, 0, -1)
# 방문한 노드일 경우 True / 방문하지 않은 노드일 경우 False
visited = [[False for _ in range(N)] for _ in range(N)]
def BFS(r, c):
q = deque() # 탐색해야 하는 노드들을 담는 큐
# 탐색을 시작하는 노드 (r, c)
q.append((r, c))
visited[r][c] = True
route = [] # 탐색 경로 저장
route.append((r, c))
# 큐에 들어가 있는 노드가 없을 때까지(탐색이 완료될 때까지) 반복
while q:
# 현재 탐색 중인 노드 (y, x)
y, x = q.popleft()
for i in range(4):
# 인접 노드 (ny, nx)
ny = y + dy[i]
nx = x + dx[i]
# 조건문을 통해 탐색 가능한 노드인지 확인
if 0 <= ny < N and 0 <= nx < N and not visited[ny][nx]:
visited[ny][nx] = True
q.append((ny, nx)) # 인접한 노드를 전부 탐색하기 위해 큐에 다시 append
route.append((ny, nx))
return route
깊이 우선 탐색 (Depth-First Search, DFS)
한 노드에서 시작하여 한 분기(branch)를 완벽하게 탐색한 후 다음 분기로 넘어가는 방식
* 최대한 깊이 내려가서 더 이상 내려갈 곳이 없을 경우 옆으로 이동
1. Stack 또는 재귀 함수를 통해 구현
2. BFS보다 구현이 간결함
3. 검색 속도는 BFS에 비해 느림
탐색 경로를 결과로 출력한다고 하면, 재귀 함수를 통한 DFS의 파이썬 구현 코드는 다음과 같다.
# N×N 2차원 배열
dy = (-1, 0, 1, 0)
dx = (0, 1, 0, -1)
# 방문한 노드일 경우 True / 방문하지 않은 노드일 경우 False
visited = [[False for _ in range(N)] for _ in range(N)]
def DFS(r, c):
# 현재 탐색 중인 노드 (r, c)
visited[r][c] = True
route = [] # 탐색 경로 저장
route.append((r, c))
for i in range(4):
# 인접 노드 (ny, nx)
ny = r + dy[i]
nx = c + dx[i]
# 조건문을 통해 탐색 가능한 노드인지 확인
if 0 <= ny < N and 0 <= nx < N and not visited[ny][nx]:
route.append((ny, nx))
DFS(ny, nx) # 재귀
return route
BFS와 DFS의 시간 복잡도
둘 다 조건 내의 모든 노드를 탐색하기 때문에 두 방식의 시간 복잡도는 동일하다.
N : 노드의 개수, E : 간선의 개수라고 했을 때
인접 리스트일 경우 O(N+E)
인접 행렬일 경우 O(N^2)로 동일하다.
BFS와 DFS를 사용하는 문제 유형
1. 모든 정점을 방문하는 것이 주요 문제일 경우
두 방식의 시간 복잡도는 동일하기 때문에 어느 것을 사용해도 무관하다.
2. 경로의 특징을 저장해야 하는 유형
(ex. 각 정점에 숫자가 적혀있고 경로에 같은 숫자가 있으면 안 되는 경우)
BFS로는 경로의 특징을 볼 수 없기 때문에 DFS를 사용한다.
3. 최단 거리를 구해야 하는 유형
BFS (가장 먼저 찾아지는 답이 최단 거리)
* 검색 대상 그래프가 크다면 DFS를 고려
* 검색 대상 규모가 크지 않고, 검색 시작 지점으로부터 원하는 대상이 별로 멀지 않다면 BFS 사용
'Computer Science & Engineering > Algorithm' 카테고리의 다른 글
[알고리즘] 분할 정복, Divide-and-Conquer (0) | 2022.12.29 |
---|---|
[알고리즘] Minimum Spanning Tree - Kruskal & Prim Algorithm (0) | 2022.12.28 |
[알고리즘] Disjoint Set & Union-Find (0) | 2022.12.25 |
[알고리즘] 배낭 문제, Knapsack Problem (0) | 2022.08.27 |
[알고리즘] 플로이드-와샬(Floyd-Warshall) 알고리즘 (0) | 2022.07.11 |