Notice
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- mqtt
- 스피커
- 공유기 포트포워딩
- 네트워크
- Type of Attacks
- 라즈비안 os
- 명령어
- 통신 프로토콜
- vm
- virtualbox
- 리눅스
- IOT
- GitHub
- mosquitto
- 라즈베리파이5
- bfg repo-cleaner
- 보안
- 부팅 스크립트
- Principles of Security
- 오블완
- linux
- ubuntu
- 마이크
- 커밋 이력
- 티스토리챌린지
- Git
- 가상머신
Archives
신짱구의 개발일지
[알고리즘] DFS(Depth First Search)이란? 본문
더보기
1. DFS 알고리즘 개념
2. DFS 알고리즘 동작 방식
3. DFS 알고리즘 구현 코드
DFS(Depth First Search) 알고리즘이란?
DFS 알고리즘은 깊이 우선 탐색 알고리즘이다. DFS는 출발 노드에서 최대한 깊이 갈 수 있는 노드까지 가보고, 더 이상 가지 못하지는 경우, 백트래킹(Back Tracking)하여 갈림길에 있는 미방문 노드부터 탐색을 시작하는 방식이다. 일반적으로, 자료구조 재귀(Recursion)와 스택(Stack)을 이용하여 문제를 해결한다.
동작 방식
DFS는 Pre-order 방식으로 그래프를 순회하는 것이 일반적이지만, 특정 문제에서는 Post-order 방식이 더 편한 경우가 있기 때문에 알아두는 것이 좋다. DFS 개념을 간단히 이해하고 싶다면 Post-order 방식은 스킵하여도 된다.
아래의 무방향 그래프 예시로 동작 방식을 자세히 살펴보자. 같은 레벨인 경우, 작은 번호 기준으로 방문한다고 가정한다.
Pre-order Traversal (전위 순회)
Pre-order Traversal은 노드를 방문하고 나서, 그 노드의 자식 노드들을 순차적으로 방문하는 방식이다.
순회 순서: 루트 -> 왼쪽 서브트리 -> 오른쪽 서브트리
- 시작 노드 1번을 스택에 넣고 방문 처리한다.
- 스택의 top에 있는 노드 1번과 인접한 노드 2번을 스택에 넣고 방문 처리한다.
- 다시 스택의 top에 있는 노드 2번과 인접한 노드 6번을 스택에 넣고 방문 처리한다.
- 위와 같은 방식으로, 노드 6번의 인접한 노드인 7번을 스택에 넣고 방문처리한다.
- 노드 7번과 인접한 방문하지 않은 노드가 없기 때문에 노드 7번을 스택에서 꺼내고, 노드 6번으로 백트래킹한다.
- 노드 6번에서도 방문하지 않은 인접 노드가 없으므로, 노드 6번을 스택에서 꺼내고, 다시 노드 2번으로 백트래킹한다.
- 노드 2번에서 인접한 노드 중 아직 방문하지 않은 8번 노드를 스택에 넣고 방문처리한다.
- ...
- 마지막으로, 스택에서 1을 꺼낸다.
Post-order Traversal (후위 순회)
Post-order Traversal은 노드의 자식 노드들을 모두 방문한 후에 현재 노드를 방문하는 방식이다.
순회 순서: 왼쪽 서브트리 -> 오른쪽 서브트리 -> 루트
- 시작 노드 1번과 인접한 노드인 2번 노드를 스택에 넣는다.
- 스택의 top에 있는 노드 2번과 인접한 노드인 6번을 다시 스택에 넣는다.
- 다시 스택의 top에 있는 노드 6번과 인접한 노드 7번을 스택에 넣는다.
- 노드 7번과 인접한 방문하지 않은 노드가 존재하지 않으므로, 노드 7번을 방문 처리하고 스택에서 꺼낸다.
- 노드 6번으로 백트래킹하고, 6번 노드와 인접한 노드가 더 이상 없기 때문에 6번 노드를 방문처리하고 스택에서 꺼낸다.
- 노드 2번으로 백트래킹하고, 인접한 노드 8번을 아직 방문하지 않았기 때문에 노드 8번을 스택에 넣는다.
- ...
- 마지막으로, 스택에 남아 있는 시작 노드 1번을 방문 처리하고 스택에서 꺼낸다.
C++ DFS 구현 코드
Recursion 버전
#include<bits/stdc++.h>
using namespace std;
bool visited[9]; // 방문 여부를 기록하는 배열
vector<int> graph[9]; // 그래프를 인접 리스트로 표현
void dfs(int x) {
visited[x] = true; // 현재 노드 방문 처리
cout << x << ' '; // 방문한 노드 출력
for (int i = 0; i < graph[x].size(); i++) {
int y = graph[x][i];
if (!visited[y]) {
dfs(y); // 방문하지 않은 노드에 대해 재귀적으로 DFS 호출
}
}
}
int main(void) {
// 그래프 초기화 (노드 간의 간선 연결)
graph[1].push_back(2);
graph[1].push_back(3);
graph[2].push_back(4);
graph[2].push_back(5);
graph[3].push_back(6);
graph[3].push_back(7);
graph[4].push_back(8);
graph[5].push_back(9);
// DFS 수행
dfs(1);
return 0;
}
Stack 버전
#include<bits/stdc++.h>
using namespace std;
bool visited[9]; // 방문 여부를 기록하는 배열
vector<int> graph[9]; // 그래프를 인접 리스트로 표현
void dfs(int start) {
stack<int> s; // DFS를 위한 스택
s.push(start); // 시작 노드를 스택에 넣음
visited[start] = true; // 시작 노드 방문 처리
while (!s.empty()) {
int x = s.top(); // 스택의 최상단 노드를 가져옴
s.pop();
cout << x << ' '; // 방문한 노드를 출력
// 현재 노드와 연결된 노드들에 대해 탐색
for (int i = graph[x].size() - 1; i >= 0; i--) {
int y = graph[x][i];
if (!visited[y]) {
s.push(y); // 스택에 인접 노드 추가
visited[y] = true; // 방문 처리
}
}
}
}
int main(void) {
// 그래프 초기화 (노드 간의 간선 연결)
graph[1].push_back(2);
graph[1].push_back(3);
graph[2].push_back(4);
graph[2].push_back(5);
graph[3].push_back(6);
graph[3].push_back(7);
graph[4].push_back(8);
graph[5].push_back(9);
// DFS 수행
dfs(1);
return 0;
}
출력 결과는 다음과 같습니다.
References
'알고리즘' 카테고리의 다른 글
[알고리즘] 순열(Permutation) (1) | 2024.09.10 |
---|---|
[알고리즘] DFS&BFS 문제: 음료수 얼려 먹기 (0) | 2024.08.24 |
[알고리즘] DFS&BFS 문제: 미로 탈출 (0) | 2024.08.24 |
[알고리즘] BFS(Breadth First Search)이란? (0) | 2024.08.21 |
[알고리즘] 그래프 알고리즘(Graph Algorithm)이란? (0) | 2024.08.21 |