깊이 우선 탐색
깊이 우선 탐색은 영어로 DFS (Depth First Search) 라 표현하며, 그래프를 탐색하는데 깊이를 우선으로 하여 탐색한다는 뜻이다. DFS 탐색을 위해선 스택이라는 자료구조가 필요하다. 스택을 사용한 DFS 탐색 방법은 아래와 같다.
DFS 순서
- 시작노드를 스택에 담는다.
- 스택의 최상단(top)에 있는 노드를 기준으로 방문되지 않은 노드중 가장 가까운 노드를 방문하고 스택에 삽입한다.
- 더 이상 진행할 수 없을 때 까지 2번 과정을 반복한다.
- 인접노드가 모두 방문되어 2번 과정이 불가능하다면 스택에서 pop을 하여 맨 위의 값을 제거한다.
- pop된 후 스택의 top의 노드를 기준으로 2 ~ 4번을 반복한다.
- 스택이 비게된다면 탐색이 완료된다.
예시
예시로 그래프가 아래와 같을 경우 (무방향 그래프, 숫자가 낮은 노드부터 탐색)
DFS로 탐색을 진행한다면 1 -> 2 -> 3 -> 5 -> 6 -> 9 -> 8 -> 7 -> 4 순 으로 탐색을 진행하게 된다.
코드
DFS 탐색을 코드로 구현할 땐 재귀를 사용하여 구현하거나 스택을 사용하여 구현한다.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package pjh5365.graph;
import java.util.Stack;
public class DFS {
    static boolean[] visited1 = new boolean[10];  // 9번 노드까지 있으므로 0빼고 사용하기 위해 10개 필요 (스택에서 사용)
    static boolean[] visited2 = new boolean[10];  // 9번 노드까지 있으므로 0빼고 사용하기 위해 10개 필요 (재귀에서 사용)
    static int[][] graph = {    // 배열별로 자신이 가르키는 노드를 가짐 (양방향 그래프임)
            {}, // 0번 사용하지 않음
            {2, 3, 4},  // 1번 노드가 가르키는 노드는 2, 3, 4
            {1},  // 2번 노드가 가르키는 노드는 1
            {1, 5}, // 3번 노드가 가르키는 노드는 1, 5
            {1}, // 4번 노드가 가르키는 노드는 1
            {3, 6, 7},  // 5번 노드가 가르키는 노드는 3, 6, 7
            {5, 9},    // 6번 노드가 가르키는 노드는 5, 9
            {5}, // 7번 노드가 가르키는 노드는 5
            {9},  // 8번 노드가 가르키는 노드는 9
            {6, 8}  // 9번 노드가 가르키는 노드는 6, 8
    };
    public static void main(String[] args) {
        System.out.println("DFS 스택사용");
        dfsStack(1);
        System.out.println("\nDFS 재귀사용");
        dfsRecursion(1);
    }
    static void dfsStack(int start) {  // 스택을 사용해 DFS 탐색
        Stack<Integer> stack = new Stack<Integer>();
        stack.push(start); // 시작인덱스를 스택에 삽입
        visited1[start] = true; // 시작인덱스는 방문함
        System.out.print(start + " -> ");
        while(!stack.isEmpty()) {  // 스택에 값이 존재한다면 계속
            int i = 0;  // 탐색하는 노드의 인접노드를 탐색하기 위한 변수
            int peek = stack.peek();   // 스택의 최상위 값 가져오기
            for(; i < graph[peek].length; i++) {    // 최상단의 인접노드를 탐색
                if(!visited1[graph[peek][i]]) {    // 방문하지 않았다면
                    visited1[graph[peek][i]] = true; // 방문 표시
                    stack.push(graph[peek][i]); // 스택에 삽입
                    System.out.print(graph[peek][i] + " -> ");    // 방문했으니 출력
                    peek = stack.peek();    // 스택의 최상위 값 다시가져오기
                    i = -1;  // 스택의 최상위 값이 변경되었으니 i 는 다시 0으로 변경하기 위해 -1로 변경 (해당 구문이 끝난 후 for 문에 의한 증가를 하므로)
                }
            }
            stack.pop();    // 탐색이 완료되어 for 문을 나와 해당 노드는 더 이상 필요하지 않으므로 pop
        }
    }
    static void dfsRecursion(int start) {   // 재귀를 사용한 DFS 탐색
        if(!visited2[start]) {   // 해당 노드가 방문되지 않았다면
            System.out.print(start + " -> "); // 출력으로 방문확인
            visited2[start] = true;  // 방문 표시
            for(int i = 0; i < graph[start].length; i++)
                dfsRecursion(graph[start][i]);    // 인접노드에 대한 dfs 탐색
        }
    }
}
결과는 아래와 같이 나온다.
 
 

