알고리즘 공부

23.06.12 Depth First Search

슈팅스타제제 2023. 6. 12. 03:49

Depth First Search (DFS)

깊이 우선 탐색

그래프 또는 트리 데이터 구조를 순회하거나 검색하는 알고리즘 

 

그래프에서의 DFS vs 트리에서의 DFS 

그래프에서는 노드를 두번 처리해버릴 수 있으므로 방문 여부를 boolean 타입으로 저장하는 배열을 사용하면 좋다!

 

DFS vs BFS

BFS 와 비교했을 때 DFS 가 어떻게 깊이 우선이 될 수 있는지 생각해보면 (너무 당연하긴 하지만 짚어보자면)

DFS 는 첫번째 노드에서 다음 노드를 탐색하는 기준이 인접 노드를 탐색 후 다음 인접 노드를 탐색하고

BFS 는 인접 노드를 모두 탐색하고 다음 노드로 넘어가기 때문에 

DFS 는 깊이 우선, BFS 는 넓이 우선이다. 

 

DFS 의 단계 

1. initialization

2. 첫번째 노드를 방문하고 아직 방문하지 않은 인접 노드를 탐색

3. 탐색한 노드 중 하나를 탐색

4. 해당 노드를 방문 처리 후 인접 노드를 탐색

5. 모든 노드를 방문할 때까지 해당 작업 반복

 

DFS 를 구현하기 위해서는 재귀 또는 스택 자료 구조를 이용할 수 있다.

재귀를 통해 반복하냐 스택으로 탐색할 노드를 관리하냐

방식만 나뉘지 깊이 우선 이라는 점은 바뀌지 않는다.

 

먼저 재귀를 이용한 코드를 살펴보면 

방문 여부를 저장하는 배열과 노드 정보를 벡터로 정의해준다. 

#include <iostream>
using namespace std;

bool visited[9];
vector<int> graph[9]; // 아직 인접 노드를 정의하기 전이므로 1차원

 

먼저 dfs 를 실행하는 함수는 다음과 같이 정의한다. 

this is 핵심~!~!

void dfs (int x) {
    visited[x] = true; // 방문 처리
    cout << x << ' ' << endl;
    
    for(int i = 0; i < graph[x].size(); i++){
        int y = graph[x][i]; // 해당 노드 (x) 에 대한 모든 인접 노드 (i) 조사
        if (!visited[y]) dfs(y); // 방문 안했으면 하고
    }
}

 

다음으로 스택 구조를 이용하면 

#include <iostream>
#include <stack>
using namespace std;

vector<int> graph[9];
stack<int> unvisited; // 스택 구조가 추가됨. 
vector<bool> visited(9, false);

가장 위 노드를 스택에서 꺼내오고 방문 처리 및 스택 제거한다. 

그리고 현재 탐색 노드에 대한 인접 노드 배열에서 방문 처리가 되지 않았다면 스택 추가한다. 

void dfs(int x) {
    int current = x;
    unvisited.push(current);
    visited[current] = true;

    while(!unvisited.empty()) {
        current = unvisited.top();
        cout << current << endl;
        visited[current] = true;
        unvisited.pop();
        for(int i: graph[current]){
            if(!visited[i]) {
                unvisited.push(i);
                visited[i] = true;
            }
        }
    }
}

 

main 함수에서 인접 노드를 설정하고 노드 1번부터 DFS 단계를 실행한다.

int main() {
    // 노드 1에 연결된 노드 정보 저장 
    graph[1].push_back(2);
    graph[1].push_back(3);
    graph[1].push_back(8);
    
    // 노드 2에 연결된 노드 정보 저장 
    graph[2].push_back(1);
    graph[2].push_back(7);
    
    // 노드 3에 연결된 노드 정보 저장 
    graph[3].push_back(1);
    graph[3].push_back(4);
    graph[3].push_back(5);
    
    // 노드 4에 연결된 노드 정보 저장 
    graph[4].push_back(3);
    graph[4].push_back(5);
    
    // 노드 5에 연결된 노드 정보 저장 
    graph[5].push_back(3);
    graph[5].push_back(4);
    
    // 노드 6에 연결된 노드 정보 저장 
    graph[6].push_back(7);
    
    // 노드 7에 연결된 노드 정보 저장 
    graph[7].push_back(2);
    graph[7].push_back(6);
    graph[7].push_back(8);
    
    // 노드 8에 연결된 노드 정보 저장 
    graph[8].push_back(1);
    graph[8].push_back(7);
    
    dfs(1); // 첫번째 노드 가쥬아
}

TODO: 연결되어 있지 않은 노드를 탐색하는 경우를 처리하는 코드 추가 필요

 

실행 결과 

각 구현 방식으로 실행했을 때, 같은 레벨의 노드에서는 랜덤으로 방문하지만 

공통적으로 깊이 우선으로 실행된 것을 확인할 수 있었다~!

## 재귀
1 2 7 6 8 3 4 5

## 스택
1 8 7 6 3 5 4 2

 

 

'알고리즘 공부' 카테고리의 다른 글

23.06.12 Breadth First Search  (0) 2023.06.12
21.12.11 XOR 연산자  (0) 2021.12.17
21.09.19 [프로그래머스] 주식 시세 차익  (0) 2021.09.22
21.09.19 [프로그래머스] 출석 이벤트  (0) 2021.09.20
21.06.11 A+B-5  (0) 2021.06.13