본문 바로가기

카테고리 없음

BFS(너비 우선 탐색)와 DFS(깊이 우선 탐색) in C#

그래프 탐색 알고리즘인 BFS(너비 우선 탐색)와 DFS(깊이 우선 탐색)는 다양한 문제 해결에 활용됩니다. 이번 글에서는 C#으로 구현한 BFS와 DFS 예제 코드와 함께 탐색 과정 테이블을 포함하여 설명하겠습니다.


그래프 구조

탐색을 수행할 그래프는 아래와 같은 구조를 가지고 있습니다.

     1
   / | \
  2  3  4
 / \  |
5   6 7

 

그래프의 인접 리스트 표현

노드 인접 노드
1 2, 3, 4
2 5, 6
3 7
4 없음
5 없음
6 없음
7 없음

BFS (너비 우선 탐색)

BFS는 가까운 노드부터 차례대로 방문하는 탐색 방법으로, **큐(Queue, FIFO)**를 활용하여 구현됩니다.

1. BFS 알고리즘 동작 방식

  1. 탐색 시작 노드를 큐에 삽입하고 방문 처리
  2. 큐에서 노드를 꺼낸 후, 해당 노드의 인접 노드를 큐에 삽입
  3. 큐가 빌 때까지 위 과정을 반복

2. BFS 예제 코드 (C#)

using System;
using System.Collections.Generic;

class Program
{
    static void BFS(Dictionary<int, List<int>> graph, int start)
    {
        HashSet<int> visited = new HashSet<int>();
        Queue<int> queue = new Queue<int>();

        queue.Enqueue(start);
        visited.Add(start);

        while (queue.Count > 0)
        {
            int node = queue.Dequeue();
            Console.Write(node + " ");

            foreach (int neighbor in graph[node])
            {
                if (!visited.Contains(neighbor))
                {
                    queue.Enqueue(neighbor);
                    visited.Add(neighbor);
                }
            }
        }
    }

    static void Main()
    {
        Dictionary<int, List<int>> graph = new Dictionary<int, List<int>>()
        {
            {1, new List<int>{2, 3, 4}},
            {2, new List<int>{5, 6}},
            {3, new List<int>{7}},
            {4, new List<int>()},
            {5, new List<int>()},
            {6, new List<int>()},
            {7, new List<int>()}
        };

        Console.WriteLine("BFS 탐색 결과:");
        BFS(graph, 1);
    }
}

3. BFS 탐색 과정 (큐 활용)

단계 큐(Queue) 상태 방문한 노드
초기 [1] -
1 [2, 3, 4] 1
2 [3, 4, 5, 6] 1, 2
3 [4, 5, 6, 7] 1, 2, 3
4 [5, 6, 7] 1, 2, 3, 4
5 [6, 7] 1, 2, 3, 4, 5
6 [7] 1, 2, 3, 4, 5, 6
7 [] 1, 2, 3, 4, 5, 6, 7

DFS (깊이 우선 탐색)

DFS는 한 경로를 끝까지 탐색한 후, 다른 경로를 탐색하는 방식으로, 스택(Stack, LIFO) 또는 재귀 함수를 활용하여 구현됩니다.

1. DFS 알고리즘 동작 방식

  1. 탐색 시작 노드를 방문하고 출력
  2. 방문한 노드의 인접 노드를 순차적으로 방문
  3. 더 이상 방문할 노드가 없으면 이전 노드로 돌아가 다른 경로 탐색

2. DFS 예제 코드 (C#)

using System;
using System.Collections.Generic;

class Program
{
    static void DFS(Dictionary<int, List<int>> graph, int node, HashSet<int> visited)
    {
        if (!visited.Contains(node))
        {
            Console.Write(node + " ");
            visited.Add(node);

            foreach (int neighbor in graph[node])
            {
                DFS(graph, neighbor, visited);
            }
        }
    }

    static void Main()
    {
        Dictionary<int, List<int>> graph = new Dictionary<int, List<int>>()
        {
            {1, new List<int>{2, 3, 4}},
            {2, new List<int>{5, 6}},
            {3, new List<int>{7}},
            {4, new List<int>()},
            {5, new List<int>()},
            {6, new List<int>()},
            {7, new List<int>()}
        };

        Console.WriteLine("DFS 탐색 결과:");
        DFS(graph, 1, new HashSet<int>());
    }
}

3. DFS 탐색 과정 (재귀 활용)

단계 현재 방문한 노드 스택(Stack) 상태 방문한 노드
초기 1 [1] -
1 1 → 2 [1, 2] 1
2 2 → 5 [1, 2, 5] 1, 2
3 5 (백트래킹) [1, 2] 1, 2, 5
4 2 → 6 [1, 2, 6] 1, 2, 5
5 6 (백트래킹) [1, 2] 1, 2, 5, 6
6 2 (백트래킹) [1] 1, 2, 5, 6
7 1 → 3 [1, 3] 1, 2, 5, 6
8 3 → 7 [1, 3, 7] 1, 2, 5, 6, 3
9 7 (백트래킹) [1, 3] 1, 2, 5, 6, 3, 7
10 3 (백트래킹) [1] 1, 2, 5, 6, 3, 7
11 1 → 4 [1, 4] 1, 2, 5, 6, 3, 7
12 4 (백트래킹) [1] 1, 2, 5, 6, 3, 7, 4
13 탐색 종료 [] 1, 2, 5, 6, 3, 7, 4

 


BFS vs DFS 비교

비교 항목 BFS (너비 우선 탐색) DFS (깊이 우선 탐색)
탐색 방식 가까운 노드부터 탐색 한 경로를 끝까지 탐색
자료구조 큐 (Queue) 스택(Stack) / 재귀(Recursion)
사용 목적 최단 거리 탐색 (가중치 없는 그래프) 백트래킹, 경로 탐색
메모리 사용량 많은 노드를 저장해야 하므로 높을 수 있음 스택 깊이에 따라 다름
실제 활용 예시 네트워크 라우팅, SNS 친구 추천 미로 찾기, 퍼즐 해결
시간 복잡도 O(V + E) O(V + E)

 


활용 예제

  • BFS 활용 예시
    • 최단 거리 탐색 (길찾기, 네트워크 라우팅)
    • SNS 친구 추천 알고리즘
    • AI 게임 탐색 (체스, 바둑 등)
  • DFS 활용 예시
    • 백트래킹 (퍼즐, 미로 찾기, 게임)
    • 웹 크롤링 (링크를 깊이 따라가는 방식)
    • 그래프의 연결 요소 찾기

면접 예상 질문

Q1: DFS와 BFS의 차이점을 설명하세요.
A1: BFS는 가까운 노드부터 탐색하는 방식이고, DFS는 한 경로를 끝까지 탐색한 후 백트래킹하는 방식입니다. BFS는 큐를 사용하고, DFS는 스택이나 재귀를 사용합니다.

Q2: BFS와 DFS의 시간 복잡도는 어떻게 되나요?
A2: 둘 다 O(V + E)의 시간 복잡도를 가집니다. V는 노드 수, E는 간선 수입니다.

Q3: DFS의 반복문 구현이 가능한가요?
A3: 네, DFS는 스택을 이용하여 반복문으로도 구현할 수 있습니다.

Q4: BFS는 어떤 상황에서 유리한가요?
A4: 최단 경로를 찾는 문제에서 유리합니다. 예를 들어, 미로 찾기나 최단 거리 탐색 문제에서 효과적입니다.

Q5: DFS를 사용할 때 주의해야 할 점은?
A5: 재귀를 사용할 경우 스택 오버플로우가 발생할 수 있으므로 깊이가 깊은 그래프에서는 반복문 기반의 DFS를 고려해야 합니다.

Q6: BFS와 DFS 중 어떤 것을 선택해야 하나요?
A6: 최단 경로를 찾을 때는 BFS가 적합하며, 백트래킹이 필요한 경우 DFS를 사용합니다.

Q7: DFS의 단점은 무엇인가요?
A7: 깊은 탐색 시 스택 오버플로우가 발생할 수 있으며, 최단 경로 탐색에는 적합하지 않습니다.

Q8: BFS를 사용할 때 주의할 점은?
A8: 큐에 많은 노드를 저장해야 하므로 메모리 사용량이 증가할 수 있습니다.


BFS와 DFS는 다양한 문제 해결에 활용할 수 있는 중요한 알고리즘입니다. 탐색 목적에 맞는 알고리즘을 선택하여 효율적인 문제 해결을 해보세요! 🚀