DFS (Depth-First Search): 가능한 깊게 들어가서 더 이상 갈 곳이 없으면 한 단계씩 되돌아오는 방식.
비유: 미로에서 한 갈래로 쭉 들어가서 막다른 길이면 뒤로 와서 다른 갈래로 간다.
BFS (Breadth-First Search): 현재 레벨(거리)에 있는 모든 노드를 먼저 방문하고, 다음 레벨로 넘어가는 방식.
비유: 물결이 퍼지듯이 가까운 곳부터 하나씩 넓게 퍼져 나간다.
-정렬된 데이터를 이분 탐색하는 것처럼 아주 효율적인 방법이 있는 반면에,
모든 경우의 수를 전부 탐색해야 하는 경우도 있다.
그래프(인접리스트):
graph = {
'A': ['B','C'],
'B': ['A','D','E'],
'C': ['A','F'],
'D': ['B'],
'E': ['B','F'],
'F': ['C','E']
}
BFS (start = A) 방문 순서(가능한 한): A → B → C → D → E → F
→ A(거리0), B,C(거리1), D,E,F(거리2) 순서
DFS (start = A, 재귀 방식, 인접 순서 사용) 방문 순서(가능한 한): A → B → D → E → F → C
→ A → B → (B의 첫 자식 D) → D 막다르면 돌아와서 E → E에서 F → 그리고 마지막에 C
def dfs_recursive(graph, node, visited=None, order=None):
if visited is None:
visited = set()
if order is None:
order = []
visited.add(node) # 들어오자마자 방문 표시
order.append(node)
for neigh in graph.get(node, []):
if neigh not in visited:
dfs_recursive(graph, neigh, visited, order)
return order
# 사용:
# dfs_recursive(graph, 'A') => ['A','B','D','E','F','C']
def dfs_iterative(graph, start):
visited = set([start])
stack = [start]
order = []
while stack:
node = stack.pop()
order.append(node)
# 재귀와 같은 순서를 원하면 이웃을 역순으로 스택에 넣음
for neigh in reversed(graph.get(node, [])):
if neigh not in visited:
visited.add(neigh)
stack.append(neigh)
return order
from collections import deque
def bfs(graph, start):
visited = set([start])
q = deque([start])
order = []
while q:
node = q.popleft()
order.append(node)
for neigh in graph.get(node, []):
if neigh not in visited:
visited.add(neigh)
q.append(neigh)
return order
# bfs(graph, 'A') => ['A','B','C','D','E','F']
from collections import deque
def bfs_shortest_path(graph, start, goal):
visited = set([start])
parent = {start: None}
q = deque([start])
while q:
node = q.popleft()
if node == goal:
# 경로 재구성
path = []
while node is not None:
path.append(node)
node = parent[node]
return list(reversed(path))
for neigh in graph.get(node, []):
if neigh not in visited:
visited.add(neigh)
parent[neigh] = node
q.append(neigh)
return None # 경로 없음
# bfs_shortest_path(graph, 'A', 'F') => ['A','C','F'] (인접 순서에 따라 달라질 수 있음)
주의: visited는 노드를 큐(또는 스택)에 넣을 때 표시하는 게 중복 enqueue/push를 막아 효율적입니다.
시간: O(V + E) (V = 정점 수, E = 간선 수) — 인접 리스트 기준
공간: 방문 체크, 큐/스택, 재귀 호출 스택 등으로 O(V)
(인접 행렬이면 시간/공간 조건이 달라짐: 행렬 접근은 O(1)지만 전체 탐색에 O(V^2))
“가장 가까운” 것을 찾는 문제 (예: 탈출까지의 최소 단계).