BFS
- 모든 노드를 너비를 우선으로 방문하기 위한 알고리즘
- 모든 간선의 길이가 동일한 상황에서 두 지점 사이의 거리를 찾는 문제는 BFS로 해결 가능
- 인접 리스트, 인접 행렬로 풀이 가능
BFS 연결 그래프 순회 (인접 리스트 방식)
const adj = new Array(10).fill(0).map(() => []);
const vis = new Array(10).fill(false);
function bfs() {
const q = [];
// 시작 노드를 큐에 넣고 방문 처리
q.push(1);
vis[1] = true;
// 큐가 비어있지 않은 동안 반복
while (q.length > 0) {
// 큐의 맨 앞 노드를 가져오기
const cur = q.shift();
// 현재 노드 출력
console.log(cur);
// 인접 노드 순회
for (const nxt of adj[cur]) {
// 이미 방문한 노드라면 건너뛰기
if (vis[nxt]) continue;
// 방문하지 않은 노드라면 큐에 추가하고 방문 처리
q.push(nxt);
vis[nxt] = true;
}
}
}
연결 그래프에서 1번 정점까지의 거리
const adj = new Array(10).fill(0).map(() => []);
const dist = new Array(10).fill(-1);
function bfs() {
const q = [];
// 1번 노드부터 탐색 시작
q.push(1);
dist[1] = 0; // 시작 노드의 거리를 0으로 설정
// 큐가 비어 있지 않은 동안 반복
while (q.length > 0) {
const cur = q.shift(); // 현재 노드
// 인접한 노드 순회
for (const nxt of adj[cur]) {
// 이미 방문한 노드(거리가 -1이 아닌 경우)는 건너뛰기
if (dist[nxt] !== -1) continue;
// 큐에 다음 노드를 추가
q.push(nxt);
// 거리 갱신
dist[nxt] = dist[cur] + 1;
}
}
}
연결 그래프가 아닐 때 순회
const adj = new Array(10).fill(0).map(() => []);
const vis = new Array(10).fill(false);
const v = 9; // 정점의 수
function bfs() {
const q = [];
// 모든 정점을 순회, 아직 방문하지 않은 정점에서 BFS 시작
for (let i = 1; i <= v; i++) {
// 이미 방문한 정점이면 건너뜁니다.
if (vis[i]) continue;
// 새로운 시작점을 큐에 넣고 방문 처리
q.push(i);
vis[i] = true;
// 큐가 비어 있지 않은 동안 반복
while (q.length > 0) {
const cur = q.shift();
// 현재 노드 출력
console.log(cur);
// 인접한 노드들을 순회
for (const nxt of adj[cur]) {
// 이미 방문한 노드라면 건너뜁니다.
if (vis[nxt]) {
continue;
}
// 방문하지 않은 노드라면 큐에 추가하고 방문 처리
q.push(nxt);
vis[nxt] = true;
}
}
}
}
DFS
- 모든 정점을 깊이 우선으로 순회할 수 있는 알고리즘
- 재귀를 이용해서 풀이 가능 → 재귀 특성상 LIFO로 호출되기때문에 stack과 같다는 특성이 있음 (호출 스택 이용)
- 스택 영역의 메모리 제한을 1MB, 10MB로 작게 제한을 걸어두면 재귀대신 stack을 사용하기 => 깊이가 깊어지면 스택메모리가 버티지 못함
DFS 스택 방식
const adj = new Array(10).fill(0).map(() => []);
const vis = new Array(10).fill(false);
function dfs() {
// 스택을 위한 배열
const s = [];
// 시작 노드를 스택에 넣고 방문 처리
s.push(1);
vis[1] = true;
// 스택이 비어있지 않은 동안 반복
while (s.length > 0) {
// 스택의 마지막 노드를 가져오기
const cur = s.pop();
// 현재 노드 출력
console.log(cur);
// 인접한 노드들을 순회
for (const nxt of adj[cur]) {
// 이미 방문한 노드라면 건너뛰기
if (vis[nxt]) continue;
// 방문하지 않은 노드라면 스택에 추가하고 방문 처리
s.push(nxt);
vis[nxt] = true;
}
}
}
DFS 재귀 방식
const adj = new Array(10).fill(0).map(() => []);
const vis = new Array(10).fill(false);
function dfs(cur) {
// 현재 노드를 방문 처리
vis[cur] = true;
// 현재 노드 출력
console.log(cur);
// 인접한 노드들을 순회
for (const nxt of adj[cur]) {
// 이미 방문한 노드라면 건너뛰기
if (vis[nxt]) continue;
// 방문하지 않은 노드라면 재귀적으로 DFS 호출
dfs(nxt);
}
}
재귀 방식과 비재귀 방식의 DFS 방문순서 차이
- 비재귀 방식으로 구현 시 스택에 값을 넣을때 노드를 방문처리하면 아래와같이 방문순서가 달라짐!
- 따라서 전통적인 DFS 방식으로 방문순서가 정해지길 원한다면 스택에서 값을 뽑을때 방문처리를 해줘야함 (아래코드 참고)

const adj = new Array(10).fill(0).map(() => []);
const vis = new Array(10).fill(false);
function dfs() {
const s = [];
s.push(1);
while (s.length > 0) {
const cur = s.pop();
// 꺼낸 후 방문 여부를 확인하고, 방문하지 않았다면 탐색을 계속
if (vis[cur]) continue;
vis[cur] = true;
console.log(cur);
// 인접 노드를 스택에 추가
for (const nxt of adj[cur]) {
if(vis[nxt]) continue;
s.push(nxt);
}
}
}'알고리즘 > 알고리즘 메모장' 카테고리의 다른 글
| [자료구조] 그래프 (0) | 2025.09.09 |
|---|
