TIL/Python

[TIL] DFS 깊이 우선 탐색 BFS 너비 우선 탐색

아람2 2024. 9. 21. 19:44
반응형

그래프를 탐색하는 방법에는

DFS 깊이 우선 탐색과 BFS 너비 우선 탐색이 있다

 

그래프에 대한 설명은 그래프 종류와 표현 방식에 정리해 놨다 

1. DFS

Depth-First Search, 깊이 우선 탐색 

최대한 깊이 내려가고, 더 이상 깊이 내려갈 곳이 없을 경우 옆으로 이동

모든 노드를 방문하는 경우에 사용한다 

* 스택 또는 재귀를 이용해서 구현 

시간 복잡도 - 인접 리스트 O(V+E), 인접 행렬 O(V^2) 

 

출처 위키

 

DFS 기본 원칙

"앞으로 찾아 가야할 노드" 와 "이미 방문한 노드" 를 기준으로 데이터 탐색한다

경로 찾기, 탐색 문제, 백트래킹, 사이클 탐지 등에 유용하다 

DFS 코드 구현

모양 출처 https://coder-narak.tistory.com/33

탐색 순서

1 - 2 - 4 - 5 - 3 - 6 
4 방문 후 2로 백트래킹하여 5를 방문하고, 다시 2 - 1로 백트래킹하여 3과 6을 방문한다 

 

1. 스택 자료 구조 이용 

def dfs(graph, start):
    # 방문 여부를 기록하는 리스트
    visited = [False] * len(graph)
    # 스택 초기화 (시작 노드 넣기)
    stack = [start]

    while stack:
        # 스택에서 노드를 꺼냄
        v = stack.pop()

        # 방문하지 않았다면 방문 처리
        if not visited[v]:
            print(v, end=' ')  # 방문하지 않았다면 방문 처리
            visited[v] = True

            # 연결된 노드를 스택에 추가 
            # stack 은 LIFO 기 때문에 역순으로 넣어야 DFS 순서와 일치
            for neighbor in reversed(graph[v]):
                if not visited[neighbor]:
                    stack.append(neighbor)

# 예시 그래프 (인접 리스트로 표현)
graph = [
    [],           # 0번 노드는 사용하지 않음 (노드 번호를 1부터 시작하기 위해)
    [2, 3],       # 1번 노드와 연결된 노드들
    [4, 5],       # 2번 노드와 연결된 노드들
    [1, 6],       # 3번 노드와 연결된 노드들
    [2],          # 4번 노드와 연결된 노드들
    [2],          # 5번 노드와 연결된 노드들
    [3],          # 6번 노드와 연결된 노드들
]

# DFS 비재귀적 호출
dfs(graph, 1)
# 줄바꿈
print()

# 결과 출력
# 1 2 4 5 3 6

스택에 추가할 때 주의할 점 

not visited[neighbor] 인 노드를 역순으로 추가해준다 

Stack 은 LIFO 구조이기 때문에 역순으로 추가해야 작은 번호인 노드부터 탐색하게 된다

 

2. 재귀 이용 

# DFS 메서드 정의
def dfs(graph, v, visited):
    # 현재 노드를 방문 처리
    visited[v] = True
    print(v, end = ' ')
    # 현재 노드와 연결된 다른 노드를 재귀적으로 방문
    for i in graph[v]:
    	# 인접 노드 중 아직 방문하지 않은 노드가 있다면 재귀 호출 
        if not visited[i]:
            dfs(graph, i, visited)

# 각 노드가 연결된 정보를 리스트 자료형으로 표현 (2차원 리스트)
graph = [
    [],          # 0번 노드는 사용하지 않음 (노드 번호를 1부터 시작하기 위해)
    [2, 3],      # 1번 노드와 연결된 노드들
    [4, 5],      # 2번 노드와 연결된 노드들
    [1, 6],      # 3번 노드와 연결된 노드들
    [2],         # 4번 노드와 연결된 노드들
    [2],         # 5번 노드와 연결된 노드들
    [3],         # 6번 노드와 연결된 노드들
]

# 각 노드가 방문된 정보를 리스트 자료형으로 표현 (방문 기록)
visited = [False] * 7

# 정의된 DFS 함수 호출, 1번 노드부터 탐색 시작 
dfs(graph, 1, visited)

 

2. BFS

Breadth-First Search, 너비 우선 탐색 

최대한 넓게 이동하고, 더 이상 갈 수 없을 때 아래로 이동

시작 정점으로부터 가까운 정점을 먼저 방문하고 떨어져 있는 정점을 나중에 방문하는 순회 방법  

주로 두 노드 사이의 최단 경로를 찾고 싶을 때 BFS 사용 

* 큐를 이용해서 구현
시간 복잡도 - 인접 리스트 O(V+E), 인접 행렬 O(V^2) 

출처 developer-mac.tistory.com/64

 

 BFS 기본 원칙

"현재 노드의 인접 노드" 를 기준으로 탐색한다 

최단 경로 찾기, 레벨 탐색, 최소 이동 거리 계산 등에 유용하다 

BFS 코드 구현

모양 출처 https://coder-narak.tistory.com/33

탐색 순서

1 - 2 - 3 - 4 - 5 - 6
0 레벨 (1) - 1 레벨 (2, 3) - 2 레벨 (4, 5, 6) 순으로 방문한다 

 

1. 큐 구조 이용 (우선순위 큐 사용)

from collections import deque

def bfs(graph, start):
    # 방문 여부를 기록하는 리스트 
    # 각 노드에 대해 방문했는지 여부를 표시 
    visited = [False] * len(graph)
    # 큐 초기화 (시작 노드 넣기)
    # deque 를 생성하기 위해 인자로 리스트를 전달 
    queue = deque([start])

    while queue:
        # 큐에서 노드를 꺼냄
        v = queue.popleft()

        # 방문하지 않았다면 방문 처리
        if not visited[v]:
            print(v, end=' ')   # 방문하지 않았다면 방문 처리
            visited[v] = True   # 방문한 노드 표시 

            # 연결된 노드를 큐에 추가 
            for neighbor in graph[v]:
                if not visited[neighbor]: # 아직 방문하지 않은 이웃 노드
                    queue.append(neighbor) # 이웃 노드를 큐에 추가 

if __name__ == '__main__':
    # 예시 그래프 (인접 리스트로 표현)
    graph = [
        [],          # 0번 노드는 사용하지 않음 (노드 번호를 1부터 시작하기 위해)
        [2, 3],      # 1번 노드와 연결된 노드들
        [4, 5],      # 2번 노드와 연결된 노드들
        [1, 6],      # 3번 노드와 연결된 노드들
        [2],         # 4번 노드와 연결된 노드들
        [2],         # 5번 노드와 연결된 노드들
        [3],         # 6번 노드와 연결된 노드들
    ]

    # BFS 비재귀적 호출
    bfs(graph, 1)
    # 줄바꿈
    print()

    # 결과 출력
    # 1 2 3 4 5 6

dfs 와 달리, 큐 (스택) 초기화 시 queue = deque([start]) 처럼 괄호를 넣는 이유

deque 는 deque 객체를 생성하는데 사용되며, 초기화할 때 인자로 iterable 한 자료 구조 (리스트, 튜플 등) 을 받는다

괄호 없이 deque 를 사용하면 start 노드 하나만으로 deque 를 만들 수 없기 때문에, 괄호 안에 리스트 형태로 제공해준다 

반응형