[이코테] 탐색 알고리즘 DFS/BFS

2024. 4. 9. 23:54·코테

DFS

depth-first Search의 약자. 깊이 우선 탐색이라고도 부르며, 그래프에서 깊은 부분을 우선적으로 탐색하는 알고리즘.

먼저 그래프의 기본 구조를 알아야 하는데, 그래프는 노드와 간선으로 표현되며 이때 노드를 정점이라고도 함.

 

그래프 탐색이란?

 

하나의 노드를 시작으로 다수의 노드를 방문하는 것. 두 노드가 간선으로 연결되어 있다면 '두 노드는 인접하다' 라고 표현

프로그래밍에서 그래프는 크게 2가지 방식으로 표현할 수 있음.

  • 인접 행렬
  • 인접 리스트

인접 행렬

  • 2차원 배열에 각 노드가 연결된 형태를 기록하는 방식.
  • 연결된 그래프를 인접 행렬로 표현할 때 파이썬에서는 2차원 리스트로 구현.
  • 연결이 되지 않은 노드끼리는 무한의 비용이라고 작성함.
  • 실제 코드에선 정답이 될 수 없는 큰 값 중에서 99999999 등으로 초기화 하는 경우가 많음.
  0 1 2
0 0 7 5
1 7 0 무한
2 5 무한 0

이렇게 인접 행렬 방식으로 처리할 때는 다음과 같이 데이터 초기화.

INF = 999999999

graph = [
	[0,7,5],
    [7,0,INF],
    [5,INF,0]
]

print(graph)

 

인접 리스트

다음 그림처럼 모든 노드에 연결된 노드에 대한 정보를 차례대로 연결하여 저장.

 

 

인접 리스트는 '연결 리스트'라는 자료구조를 이용해 구현. c++이나 자바와 같은 프로그래밍 언어에서는 별도로 연결 리스트 기능을 위한 표준 라이브러리를 제공함. 파이썬은 배열이 연결리스트의 기능까지 제공. 다음은 예제 그래프를 인접 리스트 방식으로 처리할 때 데이터를 초기화 한 코드.

# 행이 3개인 2차원 리스트로 인접 리스트 표현
graph = [[] for _ in range(3)]

# 노드 0에 연결된 노드 정보 저장(노드, 거리)
graph[0].append((1,7))
graph[0].append((2,5))

graph[1].append((0,7))

graph[2].append((0,5))

print(graph)

 

두 방식의 차이

메모리 측면에서 인접 행렬 방식은 모든 관계를 저장하므로 노드 개수가 많을수록 메모리가 불필요하게 낭비됨. 반면에 인접 리스트 방식은 연결된 정보만을 저장하기 때문에 메모리를 효율적으로 사용함. 하지만 이와 같은 속성 때문에 인접 리스트 방식은 인접 행렬 방식에 비해 특정한 두 노드가 연결되어 있는지에 대한 정보를 얻는 속도가 느림. 인접 리스트 방식에서는 연결된 데이터를 하나씩 확인해야 하기 때문.

 

예시로, 노드 1과 노드 7이 연결되어 있는 그래프에서

인접 행렬 방식 = graph[1][7]만 확인하면 됨.

인접 리스트 = 노드 1에 대한 인접 리스트를 앞에서부터 차례대로 확인

 

DFS

깊이 우선 탐색 알고리즘으로 특정한 경로로 탐색하다가 특정한 상황에서 최대한 깊숙히 들어가서 노드를 방문 후 다시 돌아가 다른 경로로 탐색하는 알고리즘.

구체적인 동작과정은 다음과 같다.

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

위 그래프를 java로 구현한 코드이다.

public static void main(String[] args) {
    ArrayList<ArrayList<Integer>> graph = new ArrayList<>();
    int[][] a = {{}, {2, 3, 8}, {1, 7}, {1, 4, 5}, {3, 5}, {3, 4}, {7}, {2, 6, 8}, {1, 7}};
    boolean[] visited = new boolean[1000];
    for (int[] n : a) {
        ArrayList<Integer> temp = new ArrayList<>();
        for (int n2 : n) {
            temp.add(n2);
        }
        graph.add(temp);
    }

    dfs(graph, 1, visited);
}
public static void dfs(ArrayList<ArrayList<Integer>> graph, int v, boolean[] visited) {
    visited[v] = true;
    System.out.print(v + " ");

    for (Integer i : graph.get(v)) {
        if (!visited[i]) {
            dfs(graph, i, visited);
        }
    }
}

BFS

너비 우선 탐색 알고리즘으로 가까운 노드부터 탐색하는 알고리즘. 큐를 이용하는 것이 정석.

인접한 노드를 반복적으로 큐에 넣도록 알고리즘을 작성하면 자연스럽게 먼저 들어온 것이 먼저 나가게 되어 가까운 노드부터 탐색을 진행하게 됨.

정확한 동작 방식은 다음과 같음

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

deque 라이브러리를 사용하는 것이 좋으며 탐색을 수행함에 있어 O(N)의 시간이 소요됨.

일반적인 경우 실제 수행 시간은 dfs보다 좋은 편.

아래는 위 그래프를 java로 구현한 코드이다.

static int[][] graph = {{}, {2, 3, 8}, {1, 7}, {1, 4, 5}, {3, 5}, {3, 4}, {7}, {2, 6, 8}, {1, 7}};
static boolean[] visited = new boolean[graph.length];

public static void main(String[] args) {
    bfs(1);
}

public static void bfs(int start) {
    Deque<Integer> deque = new LinkedList<>();
    deque.offer(start);
    visited[start] = true;
    while (!deque.isEmpty()) {
        int n = deque.pollFirst();
        System.out.print(n + " ");
        for (int i : graph[n]) {
            if (!visited[i]) {
                deque.offer(i);
                visited[i] = true;
            }
        }
    }
}

'코테' 카테고리의 다른 글

[패캠] 완전탐색 & 시뮬레이션  (0) 2024.06.07
백준 5179번 : 우승자는 누구?  (0) 2024.04.21
백준 18111번 : 마인크래프트  (0) 2024.04.07
[이코테] 꼭 필요한 자료구조 기초  (0) 2024.04.05
백준 1195번 : 킥다운  (1) 2024.01.09
'코테' 카테고리의 다른 글
  • [패캠] 완전탐색 & 시뮬레이션
  • 백준 5179번 : 우승자는 누구?
  • 백준 18111번 : 마인크래프트
  • [이코테] 꼭 필요한 자료구조 기초
Developer03
Developer03
일학습병행제로 SI 기업에 앞으로 4년간 묶여버린 개발자입니다..
  • Developer03
    SI 개발자의 Job다한 이야기
    Developer03
  • 전체
    오늘
    어제
  • Github
    • 분류 전체보기 (39)
      • 일상 (3)
      • Back-End (1)
        • Spring (1)
        • JAVA (0)
        • DATABASE (0)
      • Front-End (1)
        • JSP (0)
        • JAVASCRIPT (1)
      • DEVOPS (2)
      • Data Analysis (1)
      • 강의 (0)
        • 스프링 입문 - 코드로 배우는 스프링 부트 (0)
      • 코테 (18)
      • 학교 (6)
        • 자료구조와 알고리즘 (6)
      • 프로젝트 (2)
      • 기타 (2)
      • 회사 (2)
        • 업무 (1)
        • 과제 (1)
      • 공기업 준비 (1)
        • 토익 (0)
        • NCS (0)
        • 전공필기 (0)
        • 면접 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.1
Developer03
[이코테] 탐색 알고리즘 DFS/BFS
상단으로

티스토리툴바