우매함의 봉우리를 넘어서며 개발하면서 기록하기

DFS,BFS 알고리즘


그래프 탐색

하나의 정점으로부터 시작하여 차례로 모든 정점을 한번씩 방문하는 것


깊이 우선 탐색

DFS

깊이 우선 탐색이란

그래프 전체를 탐색하는 방법중 하나로써 시작점부터 다음 분기점으로 넘어가기 전에 해당 분기를 완벽하게 탐색하고 넘어가는 방법이다. 갈림길을 만났을 때, 한 방향으로 끝까지 간 이후에 돌아와서 다른 방향으로 끝까지 가보는 것과 유사하다.

사용시 장점

  • 현재 경로 위에 있는 노드들만 방문배열에 저장하면 되므로 메모리가 비교적 적게 사용된다.
  • 모든 노드를 탐색해볼 때 유용하다.
  • 구현이 너비 우선 탐색(BFS)보다 비교적 간단하다.

사용시 유의 사항

  • 목표로 하는 값을 구하면 탐색을 종료하므로 이 값이 최소값(최단 경로)이 된다는 보장이 없다.
  • 재귀의 형태를 띄고 있기에 노드의 방문 여부를 확인하지 않으면 무한 루프에 빠질 위험이 있디.

활용 문제

도영이가 만든 맛있는 음식 - 풀이


DFS 수도 코드 구현


코드 펼치기

void search(Node root) {
  // 더이상 갈 수 있는 노드가 없으면 return
  if (root == null) return;
  // 1. root 노드 방문하여 작업 
  do(root);
  visited[root] = true; // 1-1. 방문한 노드를 표시
  // 2. root 노드와 인접한 정점을 모두 방문
  for each (Node n in adjacent[root]) {
    if (visited[n] == false) { // 4. 방문하지 않은 정점을 찾는다.
      search(n); // 3. root 노드와 인접한 정점 정점을 시작 정점으로 DFS를 시작
    }
  }
}


넓이 우선 탐색

BFS

넓이 우선 탐색이란

루트 노드(혹은 다른 임의의 노드)에서 시작허여 가까운 노드를 먼저 탐색하고 멀리 떨어져있는 노드를 나중에 방문하는 방법이다.

사용시 장점

  • 두 노드 사이의 최단 경로를 찾을 때 이 방법을 사용한다.
  • Prim, Dijkstra 알고리즘과 유사하다.

사용시 유의 사항

  • 단계별로 탐색하기 때문에 직관적이지 못하다.
  • 노드의 방문 여부를 확인하지 않으면 무한 루프에 빠질 위험이 있다.

활용 문제

아기 상어 - 풀이


BFS 수도코드 구현


코드 펼치기

void search(Node root) {
  Queue queue = new Queue();
  visited[root] = true; // (방문한 노드 체크)
  queue.enqueue(root); // 1-1. 큐의 끝에 추가

  // 3. 큐가 소진될 때까지 계속한다.
  while (!queue.isEmpty()) {
    Node now = queue.dequeue(); // 큐의 앞에서 노드 추출
    do(now); // 2-1. 큐에서 추출한 노드 방문하여 작업

    // 2-2. 큐에서 꺼낸 노드와 인접한 노드들을 모두 차례로 방문한다.
    foreach (Node n in adjacent[now]) {
      if (visited[n] == false) {
        visited[n] = true; // (방문한 노드 체크)
        queue.enqueue(n); // 2-3. 다음 노드 큐의 끝에 추가
      }
    }
  }
}


참고자료

https://www.geeksforgeeks.org/depth-first-search-or-dfs-for-a-graph/ https://www.geeksforgeeks.org/breadth-first-search-or-bfs-for-a-graph/ https://www.freelancinggig.com/blog/2019/02/06/what-is-the-difference-between-bfs-and-dfs-algorithms/