Search

DFS & BFS

생성일
2023/02/02 06:23
태그
C++

DFS & BFS

DFS

시작점부터 다음 branch로 넘어가기 전에 해당 branch를 완벽하게 탐색하고 넘어가는 방법

[재귀함수][스택]으로 구현

1.
탐색 시작 노드를 스택에 삽입하고 방문처리
2.
스택의 최상단 노드에 방문하지 않은 인접한 노드가 하나라도 있으면, 그 노드를 스택에 넣고 방문처리, 방문하지 않은 인접 노드가 없으면, 스택에서 최상단 노드를 꺼낸다
3.
2번의 과정을 수행할 수 없을 때까지 반복
노드 방문 시 방문(visited) 여부를 반드시 검사해야 한다. 아니면 무한루프에 빠질 수 있다
탐색 과정이 시작 노드에서 한없이 깊이 진행되는 것을 막기 위해 제한(depth bound)를 사용
깊이 제한에 도달할 때까지 목표노드가 발견되지 않으면, 최근에 첨가된 노드의 부모노드로 돌아와서(백트래킹-backtracking), 부모노드에 이전과는 다른 동작자를 적용하여 새로운 자식노드를 생성

장점

단지 현 경로상의 노드만을 기억하면 되므로, 저장공간의 수요가 비교적 적다
목표노드가 깊은 단계에 있을 경우, 해를 빨리 구할 수 있다

단점

해가 없는 경로에 깊이 빠질 가능성이 있다.
따라서 실제의 경우 미리 지정한 임의의 깊이까지만 탐색하고, 목표노드를 발견하지 못하면 다음 경로를 따라 탐색하는 방법이 유용할 수도 있다
얻어진 해가 최단 경로가 된다는 보장이 없다.
이는 목표에 이르는 경로가 다수인 문제에 대해 DFS는 해에 다다르면 탐색을 끝내버리므로, 이때 얻어진 해는 최적이 아닐 수도 있다

알고리즘

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]) { // 방문하지 않았으면 즉, visited가 false일 때, not을 해주면 true가 되므로 아래 dfs 실행 dfs(y); // 재귀적으로 방문 } } }
C++
복사

BFS

시작 노드를 방문한 후, 시작 노드에 있는 인접한 모든 노드들을 우선 탐색
최단 경로 탐색 or 임의의 경로 탐색
더이상 방문하지 않은 노드가 없을 때까지 방문하지 않은 모든 노드에 대해서도 BFS를 적용한다

[큐]를 이용하여 구현

그래프에서 가장 가까운 노드부터 우선적으로 탐색하는 알고리즘
1.
탐색 시작 노드를 큐에 삽입하고 방문 처리
2.
큐에서 노드를 꺼낸 뒤에 해당 노드의 인접 노드 중 방문하지 않은 노드를 모두 큐에 삽입 후 방문 처리
3.
2번 반복
→ 특정 조건의 최단 경로 알고리즘을 계산할 때 사용

장점

출발노드에서 목표노드까지의 최단 길이 경로를 보장

단점

경로가 매우 길 경우에는 탐색 가지가 급격히 증가함에 따라 보다 많은 기억 공간이 필요
해가 존재하지 않는다면, 유한그래프의 경우 모든 그래프를 탐색한 후에 실패로 끝난다
무한그래프의 경우에는 결코 해를 찾지도 못하고, 끝내지도 못한다

알고리즘

void bfs(int start) { queue<int> q; q.push(start); // 첫 노드를 queue에 삽입 visited[start] = true; // 첫 노드를 방문 처리 // 큐가 빌 때까지 반복 while (!q.empty()) { // 큐에서 하나의 원소를 뽑아 출력 int x = q.front(); q.pop(); cout << x << " "; // 해당 원소와 연결된, 아직 방문하지 않은 원소들을 큐에 삽입 for (int i = 0; i < graph[x].size(); i++) { int y = graph[x][i]; if (!visited[y]) { q.push(y); visited[y] = true; } } } }
C++
복사

그래프 표현 방식

1. 인접 행렬 : 2차원 배열로 그래프 표현

[i]에서 [j] 방향으로 연결 되어 있으면 1, 아니면 0 처리
장점
구현 쉽다
연결 여부 확인하기 용이
arr[i][j]가 1인지 0인지만 알면 된다
단점
노드 [i]와 연결된 모든 노드들에 방문해보고 싶을 때, arr[i][1]부터 arr[i][전체노드개수]를 모두 확인해봐야하기 때문에 시간복잡도가 크다

2. 인접 리스트 : 리스트로 그래프 표현

인접리스트는 그래프의 연결 리스트의 자료구조를 이용하여 구현
c++에선 vector를 사용하여 구현
arr[i] : 노드 i에 연결된 노드들을 원소로 같는 리스트

Reference