[알고리즘] DFS / BFS

good_da22·2022년 2월 4일
0

python for coding test

목록 보기
4/10
post-thumbnail

그래프

노드(Node)간선(Edge)로 표현되며 노드를 정점(Vertex)라고도 말한다.
두 노드가 간선으로 연결되어 있는 경우 두 노드는 인접(Adjacent)하다.

프로그래밍에서 그래프를 표현하는 방식

인접 행렬(Adjacency Matrix) : 2차원 배열로 그래프의 연결 관계를 표현하는 방식
인접 리스트(Adhacency list) : 리스트로 그래프의 연결 관계를 표현하는 방식

탐색 문제의 경우 그래프 형태로 표현한 다음 풀이법을 고민하자

인접 행렬

2차원 바열에 각 노드가 연결된 형태를 기록하는 방식

연결이 되어 있는 경우 거리(거리가 없는 경우 1)를 작성
자기 자신에 해당하는 경우 0
연결이 되어 있지 않은 노드끼리는 무한(Infinity)의 비용으로 작성

인접 리스트

연결 리스트라는 자료구조를 이요하여 구현
C++과 자바의 경우 별도의 연결 리스트 기능을 위한 표준 라이브러리를 제공
파이썬의 경우 2차원 리스트를 활용

각 노드에 연결된 노드의 정보를 저장한다.

인접 행렬 vs 인접 리스트

메모리 측면에서

인접 행렬은 모든 관계를 저장, 노드 개수가 많을 수록 메모리가 불필요하게 낭비
인접 리스트는 연결된 정보만을 저장, 메모리를 효율적으로 사용

특정한 노드와 연결된 모든 인접 노드를 순회하는 경우, 인접 리스트 방식이 인접 행렬 방식에 비해 메모리 공간의 낭비가 적다.

속도 측면에서

인접 행렬은 특정 두 노드가 연결되어 있는지에 대한 정보를 얻는 속도가 빠르다.
인접 리스트는 연결된 데이터를 하나씩 확인해야 하기 때문에 느리다.

특정한 두 노드사이의 연결 정보를 원하는 경우, 인접 행렬 방식이 인접 리스트 방식에 비해 속도가 빠르다.

DFS

Depth First Search, 깊이 우선 탐색이란 그래프에서 깊은 부분을 우선적으로 탐색하는 알고리즘
특정한 경로로 탐색하다가 특정한 상황에서 최대한 깊숙이 들어가서 노드를 방문하 후, 다시 돌오가 다른 경로로 탐색하는 알고리즘

스택 자료구조를 이용한 동작 과정

1. 탐색 시작 노드를 스택에 삽입하고 방문 처리
2. 스택의 최상단 노드에 방문하지 않은 인접 노드가 있으면 그 인접 노드를 스택에 넣고 방문 처리를 한다.
방문하지 않은 인접 노드가 없으면 스택에서 최상단 노드를 꺼낸다.
3. 2번의 과정을 더 이상 수행할 수 없을 때까지 반복한다.

관행적으로 번호가 낮은 순서로부터 처리하도록 구현한다.

탐색을 수행함에 있어 데이터 개수가 N개인 경우 O(N) 의 시간이 소요된다.

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

BFS

Breadth First Search, 너비 우선 탐색이란 가까운 노드부터 탐색하는 알고리즘
최대한 멀리 있는 노드를 우선적으로 탐색하는 DFS와 반대
선입선출 방식인 자료구조를 이용한다.
인접한 노드를 반복적으로 큐에 넣도록 알고리즘을 작성하면 먼저 들어온 것이 먼저 나가게 되어, 가까운 노드부터 탐색을 진행하게 된다.

1. 탐색 시작 노드를 큐에 삽입하고 방문 처리 한다.
2. 큐에서 노드를 꺼내 해당 노드의 인접 노드 중에서 방문하지 않은 노드를 모두 큐에 삽입하고 방문 처리를 한다.
3. 2번의 과정을 더 이상 수행할 수 없을 때까지 반복한다.

파이썬에서 deque 라이브러리를 사용하고 탐색을 수행함에 있어 데이터 개수가 N개인 경우 O(N) 의 시간이 소요된다.
일반적인 경우 수행 시간은 DFS보다 좋은 편

from collections import deque

#BFS 너비 우선 탐색
def bfs(graph, start, visited):
  #큐(Queue) 구현을 위해 deque 라이브러리 사용
  queue = deque([start])
  visited[start] = True #현재 노드 방문 처리
  #큐가 빌 때까지 반복
  while queue:
    v = queue.popleft() #큐에서 하나의 원소를 뽑아 출력, 선입선출
    print(v, end=' ')
    #해당 원소와 연결된, 아직 방문하지 않은 원소들을 큐에 삽입
    for i in graph[v]: #현재 노드의 인접 노드 탐색
      if not visited[i]: #인접 노드 방문여부 확인, 방문하지 않은 경우
        queue.append(i) #방문하지 않은 노드를 큐에 추가
        visited[i] = True #추가된 노드의 방문여부 체크

참고

나동빈(2020).이것이 취업을 위한 코딩 테스트다 with 파이썬.한빛미디어

profile
dev blog

0개의 댓글