깊이 우선 탐색 #
- 깊이 우선 탐색: 트리를 포함한 그래프에서 사용되는 알고리즘으로
시작 그래프에서부터 가능한 깊게 탐색해
원하는 결과값을 찾는 알고리즘입니다.
대상이 될 그래프 #
그래프를 한눈에 보기 쉽게 표현하면 아래와 같습니다.
%%{init: {'theme':'dark'}}%%
graph TD;
A-->B;
A-->C;
B-->D;
B-->E;
C-->F;
D-->G;
E-->H;
F-->I;
자바스크립트로 표현하면 아래와 같이 표현 가능합니다.
const graph = {
A: ["B", "C"],
B: ["D", "E"],
C: ["F"],
D: ["G"],
E: ["H"],
F: ["I"]
}
이제 이 그래프를 dfs를 이용해서 탐색해보겠습니다.
dfs를 이용해서 탐색하기 #
iterative한 dfs 탐색은 stack을 기반으로 탐색합니다.
위에서 예시로 든 그래프를 기반으로 탐색하는 것은 생각보다 시간이 너무 오래걸리니 그래프를 작게 다시 만들어 보겠습니다.
%%{init: {'theme':'dark'}}%%
graph TD;
A-->B
A-->C
B-->D
const graph = {
A:["B", "C"],
B: ["D"]
}
만만해진 그래프를 가지고 dfs 알고리즘을 설명하겠습니다.
dfs를 반복문으로 풀어내는 경우 stack이 사용됩니다.
dfs와 잘어울리는 stack #
stack의 표현은 링크의 설명을 참고해주세요
위 그래프를 stack을 쌓고 터트리는 과정을 통해 설명하겠습니다.
nil |
---|
A(p) |
---|
- 노드의 시작점인 A를 stack에 쌓습니다.
- stack을 pop하면서 log를 통해 내보냅니다.
- A가 가리키고 있는 노드에 대해 반복문을 돌고 차례대로 stack에 push 합니다.
C(p) |
---|
B |
- stack을 pop하면서 log를 통해 내보냅니다.
- C가 가리키고 있는 노드가 있는지 확인해보지만 C는 엣지를 가지고 있지 않습니다.
- pop되어집니다.
B(p) |
---|
- stack을 pop하면서 log를 통해 내보냅니다.
- B가 가리키고 있는 노드에 대해 반복문을 돌고 차례대로 stack에 push 합니다.
D(p) |
---|
- stack을 pop하면서 log를 통해 내보냅니다.
- D가 가리키고 있는 노드가 있는지 확인해보지만 D는 엣지를 가지고 있지 않습니다.
nil |
---|
- stack이 모두 비워졌습니다. 그래프를 모두 순회했습니다.
이미 방문한 노드를 체크하는 visited #
- 위 스택의 설명에는 나와있지 않지만 아래 dfs에선 하나의 자료구조를 더 사용합니다.
- Set입니다. 이는 이미 방문한적이 있는 node를 걸러주기 위해 존재합니다.
예를 들어 그래프를 아래와 같이 작성한다면 어떨까요?
const graph = {
A: ["B", "C"],
B: ["A"],
};
A는 B를 가리키고 C는 따로 가리키는 노드가 없습니다. B는 다시 A를 가리킵니다.
반복문에서 B는 그래프의 A를 다시 지목해 B, C를 스택에 쌓고 B를 pop할 때, B는 A를 다시 지목하여 무한 반복됩니다. 따라서 이 순환을 끊기 위해서는 이를 기록하는 visited 변수가 필요합니다.
구현 #
위 모든 과정을 코드로 표현하면 아래와 같이 표현됩니다.
function dfs(graph, start) {
const stack = [start]; // 시작 노드를 stack으로 만듭니다.
const visited = new Set(); // 방
while (stack.length) {
let currentNode = stack.pop();
visited.add(currentNode);
console.log(currentNode);
if (graph[currentNode]) {
graph[currentNode].forEach((node) => {
if (!visited.has(node)) stack.push(node);
});
}
}
}
const graph = {
A: ["B", "C"],
B: ["D"],
};
dfs(graph, "A");
정리 #
기본적인 구현은 위와 같으나 이를 다양하게 응용한 문제와 사용례들이 존재합니다.
다음엔 이를 응용한 미로탐색을 알아보겠습니다.
감사합니다.