Information Security Study
DFS 개념 본문
DFS (Depth-First Search) 개념
- DFS(Depth-First Search, 깊이 우선 탐색)는 그래프나 트리의 모든 노드를 탐색하는 알고리즘이다.
- 이 알고리즘은 한 노드에서 시작하여 가능한 깊이까지 탐색한 후 더 이상 탐색할 노드가 없으면 마지막으로 방문한 노드에서 다시 탐색을 시작한다.
DFS의 특징
- 경로 탐색: 한 경로를 가능한 깊이까지 탐색한다.
- 스택 기반: 재귀 호출이나 명시적인 스택을 사용하여 구현된다.
- 백트래킹: 더 이상 진행할 수 없는 경로를 만날 경우 이전 경로로 돌아가서 다른 경로를 탐색한다.
DFS의 장점
- 문제를 해결하기 위해 깊이 있는 경로를 탐색할 때 유용하다.
- 모든 노드를 메모리에 저장하지 않아도 되기 때문에 특정 상황에서는 메모리 사용이 적다.
DFS의 단점
- 순환이 있는 그래프에서는 무한 루프에 빠질 수 있다. 이를 방지하기 위해 방문한 노드를 추적해야 한다.
- 가장 짧은 경로를 찾는 데는 적합하지 않다.
자바에서의 DFS 구현 예제
1) 재귀를 사용한 DFS
트리나 그래프의 깊이 우선 탐색을 자연스럽게 표현한다.
import java.util.*;
public class DFSExample {
static StringBuilder sb = new StringBuilder(); // 방문 순서를 저장할 StringBuilder
static boolean[][] node; // 인접 행렬을 저장할 배열
static boolean[] visited; // 방문 여부를 저장할 배열
// DFS 함수
static void dfs(int v) {
if (visited[v])
return; // 이미 방문한 노드면 탐색 종료
visited[v] = true; // 현재 노드를 방문 처리
sb.append(v + " "); // 방문한 노드를 StringBuilder에 추가
// 현재 노드와 연결된 모든 노드를 재귀적으로 방문
for (int i = 1; i < node[v].length; i++) {
if (node[v][i] && !visited[i]) {
dfs(i);
}
}
}
public static void main(String[] args) {
int n = 5; // 그래프의 노드 수
// 인접 행렬 및 방문 배열 초기화
node = new boolean[n + 1][n + 1];
visited = new boolean[n + 1];
// 그래프의 간선 설정 (예시)
node[1][2] = node[2][1] = true;
node[1][3] = node[3][1] = true;
node[2][4] = node[4][2] = true;
node[2][5] = node[5][2] = true;
// DFS 탐색 시작 (시작 노드: 1)
dfs(1);
// 방문 순서 출력
System.out.println("DFS 방문 순서: " + sb.toString().trim()); // 방문 순서: 1 2 4 5 3
}
}
그래프 구조
1 - 2
| |
3 4
|
5
- 재귀를 사용하면 DFS를 구현할 때 자연스럽게 깊이 탐색을 할 수 있다.
- 함수가 자기 자신을 호출하는 방식으로 그래프의 깊은 부분까지 탐색한다.
작동 방식
- 현재 노드를 방문하고 결과를 저장한다.
- 현재 노드와 연결된 모든 노드 중 방문하지 않은 노드가 있으면, 그 노드를 방문하기 위해 함수 자신을 호출한다.
- 모든 연결된 노드를 탐색할 때까지 이 과정을 반복한다.
2) 스택을 사용한 DFS
재귀를 사용하지 않고 스택을 사용하여 DFS를 수행한다.
import java.util.*;
public class DFSExample {
public static String dfs(int v, boolean node[][]) {
StringBuilder sb = new StringBuilder();
Stack<Integer> stack = new Stack<>();
boolean visited[] = new boolean[node.length]; // 방문 여부 체크 배열
stack.add(v); // 시작 노드 추가
while (!stack.isEmpty()) {
int idx = stack.pop(); // 스택에서 노드를 꺼냄
if (visited[idx]) // 이미 방문한 경우 생략
continue;
visited[idx] = true; // 현재 노드 방문 처리
sb.append(idx + " "); // 방문한 노드 기록
// 인접 노드 탐색
for (int i = node.length - 1; i >= 0; i--) {
if (node[idx][i] && !visited[i]) {
stack.add(i); // 방문하지 않은 연결 노드를 스택에 추가
}
}
}
return sb.toString();
}
public static void main(String[] args) {
int n = 5; // 노드 수
boolean[][] node = new boolean[n + 1][n + 1];
// 그래프 간선 연결 설정 (예시)
node[1][2] = node[2][1] = true;
node[1][3] = node[3][1] = true;
node[2][4] = node[4][2] = true;
node[2][5] = node[5][2] = true;
// DFS 실행 및 출력
System.out.println(dfs(1, node));
}
}
- 스택을 사용하면 DFS를 명시적으로 구현할 수 있다.
- 스택은 마지막에 추가된 요소부터 제거되기 때문에 스택의 구조를 통해 깊이 우선 탐색을 한다.
작동 방식
- 시작 노드를 스택에 추가한다.
- 스택에서 노드를 꺼내어 방문한다.
- 꺼낸 노드의 인접 노드 중 방문하지 않은 노드를 스택에 추가한다.
- 스택이 비어 있을 때까지 이 과정을 반복한다.
'Programming > JAVA' 카테고리의 다른 글
[프로그래머스] 타겟 넘버(level 2, BFS) (0) | 2024.10.10 |
---|---|
BFS 개념 (0) | 2024.10.08 |
이분 탐색(Binary Search) 개념과 구현 (0) | 2024.09.17 |
[프로그래머스] 완주하지 못한 선수(level1, HashMap) (0) | 2024.09.17 |
[프로그래머스] 폰켓몬(level 1, HashSet) (1) | 2024.09.17 |