티스토리 뷰

패스트캠퍼스 코딩테스트 인터넷 강의, 잔재미코딩 님의 수업을 참고하였습니다.

BFS와 DFS란?

  • 대표적인 그래프 탐색 알고리즘
    • 너비 우선 탐색(Breadth First Search): 정점들과 같은 레벨에 있는 노드들(형제 노드들)을 먼저 탐색하는 방식
      • 두 개의 큐를 사용한다.
      • root와 가까운 node들부터 찾기 때문에 최단거리를 탐색할 때 유용하다.
      • queue에 각 노드의 정보를 기록해야 하기 때문에 메모리를 많이 잡아 먹는다.
      • 찾고자 하는 target node가 root node와 가까이 있다고 예상될 경우 BFS를 사용한다.
      • 지도 어플에서 특정 위치까지의 최단거리 안내, 혹은 소셜미디어에서 친구 추천 등에 이용된다.
    • 깊이 우선 탐색(Depth First Search): 정점의 자식들을 먼저 탐색하는 방식
      • 한 개의 큐와 한 개의 스택을 사용한다.
      • BFS보다 속도가 느릴 수 있다.
      • 미로 게임 등에서 경로가 존재하는지를 판별할 때 유용하다.

BFS/DFS 방식 이해를 위한 예제

  • BFS 방식: A - B - C - D - G - H - I - E - F - J
  • DFS 방식: A - B - D - E - F - C - G - H - I - J

출처: https://www.fun-coding.org/

자바스크립트로 그래프 표현하기

const graph = {
  A: ['B', 'C'],
  B: ['A', 'D'],
  C: ['A', 'G', 'H', 'I'],
  D: ['B', 'E', 'F'],
  E: ['D'],
  F: ['D'],
  G: ['C'],
  H: ['C'],
  I: ['C', 'J'],
  J: ['I']
};

BFS 알고리즘 구현

구현

두 개의 큐(Queue)를 활용한다.

const graph = {
  A: ["B", "C"],
  B: ["A", "D"],
  C: ["A", "G", "H", "I"],
  D: ["B", "E", "F"],
  E: ["D"],
  F: ["D"],
  G: ["C"],
  H: ["C"],
  I: ["C", "J"],
  J: ["I"]
};

const bfs = (graph, startNode) => {
  let visited = []; // 탐색을 마친 노드들
  let needVisit = []; // 탐색해야할 노드들

  needVisit.push(startNode); // 노드 탐색 시작

  while (needVisit.length !== 0) { // 탐색해야할 노드가 남아있다면
    const node = needVisit.shift(); // queue이기 때문에 선입선출, shift()를 사용한다.
    if (!visited.includes(node)) { // 해당 노드가 탐색된 적 없다면
      visited.push(node); 
      needVisit = [...needVisit, ...graph[node]];
    }
  }
  return visited;
};

console.log(bfs(graph, "A"));
// ["A", "B", "C", "D", "G", "H", "I", "E", "F", "J"]

DFS 알고리즘 구현

  • 자료구조 스택과 큐를 활용
    • needVisit 스택과 visited 큐, 두 개의 자료 구조를 생성한다.
    • 큐와 스택 구현은 별도의 라이브러리를 활용할 수도 있지만 간단히 배열을 통해 구현하자.

BFS 구조는 두 개의 큐를 활용하는데, DFS한 개의 스택과 한 개의 큐를 사용한다는 차이가 있음
BFS 구조는 이전 노드와 연결된 노드들을 먼저 탐색해야 하기 때문에 queue. DFS는 이전 노드가 아니라 자기 자신과 연결되었던 노드들 먼저 탐색하기 때문에 stack을 사용한다.

const graph = {
  A: ["B", "C"],
  B: ["A", "D"],
  C: ["A", "G", "H", "I"],
  D: ["B", "E", "F"],
  E: ["D"],
  F: ["D"],
  G: ["C"],
  H: ["C"],
  I: ["C", "J"],
  J: ["I"],
};

// (graph, 시작 정점)
const dfs = (graph, startNode) => {
  let needVisitStack = []; // 탐색을 해야 할 노드들
  let visitedQueue = []; // 탐색을 마친 노드들

  needVisitStack.push(startNode);

  // 탐색을 해야 할 노드가 남아 있다면
  while (needVisitStack.length !== 0) {
    const node = needVisitStack.pop();
    if (!visitedQueue.includes(node)) {
      visitedQueue.push(node);
      needVisitStack = [...needVisitStack, ...graph[node]];
    }
  }

  return visitedQueue;
};

console.log(dfs(graph, "A"));

// ["A", "C", "I", "J", "H", "G", "B", "D", "F", "E"]

시간복잡도

DFS와 BFS는 모두 노드 수+간선 수만큼의 복잡도를 지닌다. 즉, O(n)

'Programming > 자료구조, 알고리즘' 카테고리의 다른 글

이진 탐색  (0) 2020.04.05
순차 탐색  (0) 2020.04.05
그리디 알고리즘  (2) 2020.04.03
분할정복과 병합정렬(merge sort), 퀵 정렬(quick sort)  (0) 2020.04.01
동적계획법과 피보나치 수열  (0) 2020.03.31
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/04   »
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
글 보관함