Coding Test

μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œμ˜ BFS와 DFS

chamroro 2025. 3. 3. 20:56

1. BFS (Breadth-First Search)

BFSλŠ” μ‹œμž‘ λ…Έλ“œμ—μ„œλΆ€ν„° κ°€κΉŒμš΄ λ…Έλ“œλΆ€ν„° μ°¨λ‘€λ‘œ λ°©λ¬Έν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μž…λ‹ˆλ‹€.
보톡 큐(Queue, FIFO: First-In, First-Out)λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
μ΅œλ‹¨ 경둜, 레벨 순회 등에 μœ μš©ν•©λ‹ˆλ‹€.

function bfsWithVisited(start, getNeighbors) {
    const queue = [start];
    const visited = new Set();
    visited.add(start);
    console.log("초기 visited:", Array.from(visited));

    while (queue.length > 0) {
        const current = queue.shift(); // νμ—μ„œ κ°€μž₯ μ•žμ˜ μ›μ†Œλ₯Ό 꺼냄
        console.log("ν˜„μž¬ 처리 λ…Έλ“œ:", current);
        // ν˜„μž¬ λ…Έλ“œμ˜ 이웃듀을 순회
        for (const neighbor of getNeighbors(current)) {
          if (!visited.has(neighbor)) {
            visited.add(neighbor);
            queue.push(neighbor);
            console.log(`μƒˆλ‘­κ²Œ λ°©λ¬Έ: ${neighbor} -> visited:`, Array.from(visited));
          }
        }
    }
    return visited;
}

// 예제 κ·Έλž˜ν”„ (인접 리슀트 ν˜•νƒœ)
const graph = {
A: ['B', 'C'],
B: ['A', 'D', 'E'],
C: ['A', 'F'],
D: ['B'],
E: ['B', 'F'],
F: ['C', 'E']
};

// BFS μ‹€ν–‰ μ˜ˆμ‹œ
console.log("BFS λ°©λ¬Έ κ²°κ³Ό:");
bfsWithVisited('A', node => graph[node]);
// μ˜ˆμƒ BFS λ°©λ¬Έ μˆœμ„œ: A → B → C → D → E → F

 

 

초기 μƒνƒœμ—μ„œ μ‹œμž‘ λ…Έλ“œ Aλ₯Ό 큐와 visited에 μΆ”κ°€ν•©λ‹ˆλ‹€.
νμ—μ„œ ν•˜λ‚˜μ”© κΊΌλ‚΄λ©°, ν•΄λ‹Ή λ…Έλ“œμ˜ 이웃 쀑 아직 λ°©λ¬Έν•˜μ§€ μ•Šμ€ λ…Έλ“œλ₯Ό 큐에 μΆ”κ°€ν•©λ‹ˆλ‹€.
λ°©λ¬Έ μƒνƒœ(visited)λŠ” Set으둜 κ΄€λ¦¬ν•˜μ—¬ 쀑볡 방문을 λ§‰μŠ΅λ‹ˆλ‹€.

 


2. DFS (Depth-First Search)

DFSλŠ” ν•œ 경둜λ₯Ό κ°€λŠ₯ν•œ 깊게 νƒμƒ‰ν•œ ν›„, 더 이상 μ§„ν–‰ν•  수 μ—†μœΌλ©΄ λ°±νŠΈλž˜ν‚Ήν•˜μ—¬ λ‹€λ₯Έ 경둜λ₯Ό νƒμƒ‰ν•©λ‹ˆλ‹€.
μž¬κ·€λ‚˜ μŠ€νƒ(Stack, LIFO: Last-In, First-Out)을 μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
경둜 탐색, λ°±νŠΈλž˜ν‚Ή, 사이클 감지 등에 μœ μš©ν•©λ‹ˆλ‹€.


2.1. μž¬κ·€ 기반 DFS : ν•¨μˆ˜ 호좜 μŠ€νƒμ„ μ‚¬μš©ν•΄ 깊이 μš°μ„  탐색을 μžμ—°μŠ€λŸ½κ²Œ κ΅¬ν˜„ν•©λ‹ˆλ‹€.

function dfsRecursiveWithVisited(node, getNeighbors, visited = new Set()) {
    visited.add(node);
    console.log("ν˜„μž¬ λ°©λ¬Έ λ…Έλ“œ:", node, "-> visited:", Array.from(visited));

    for (const neighbor of getNeighbors(node)) {
        if (!visited.has(neighbor)) {
        	dfsRecursiveWithVisited(neighbor, getNeighbors, visited);
        }
    }
    return visited;
}

// DFS μ‹€ν–‰ μ˜ˆμ‹œ (μž¬κ·€ 방식)
console.log("DFS (μž¬κ·€) λ°©λ¬Έ κ²°κ³Ό:");
dfsRecursiveWithVisited('A', node => graph[node]);
// μ˜ˆμƒ DFS λ°©λ¬Έ μˆœμ„œ (μ˜ˆμ‹œ): A → B → D → E → F → C
// (탐색 μˆœμ„œλŠ” getNeighbors ν•¨μˆ˜μ˜ λ°˜ν™˜ μˆœμ„œμ— 따라 λ‹¬λΌμ§ˆ 수 있음)

 

2.2. μŠ€νƒ 기반 DFS: λͺ…μ‹œμ μΈ μŠ€νƒμ„ μ‚¬μš©ν•˜μ—¬ ν›„μž…μ„ μΆœ(LIFO) λ°©μ‹μœΌλ‘œ, λ§ˆμ§€λ§‰μ— μΆ”κ°€λœ λ…Έλ“œλΆ€ν„° μ²˜λ¦¬ν•©λ‹ˆλ‹€.

function dfsStack(start, getNeighbors) {
    const stack = [start];
    const visited = new Set();

    while (stack.length > 0) {
    const current = stack.pop(); // μŠ€νƒμ—μ„œ λ§ˆμ§€λ§‰ μš”μ†Œλ₯Ό 꺼냄 (LIFO)
    if (!visited.has(current)) {
        visited.add(current);
        console.log("ν˜„μž¬ λ°©λ¬Έ λ…Έλ“œ:", current, "-> visited:", Array.from(visited));
        // 이웃듀을 μŠ€νƒμ— μΆ”κ°€ (μˆœμ„œλŠ” 이웃 λ°°μ—΄ μˆœμ„œμ— 따라 λ‹€λ₯Ό 수 있음)
          for (const neighbor of getNeighbors(current)) {
            if (!visited.has(neighbor)) {
              stack.push(neighbor);
            }
          }
        }
    }
    return visited;
}

// DFS μ‹€ν–‰ μ˜ˆμ‹œ (μŠ€νƒ 방식)
console.log("DFS (μŠ€νƒ) λ°©λ¬Έ κ²°κ³Ό:");
dfsStack('A', node => graph[node]);
// μ˜ˆμƒ DFS λ°©λ¬Έ μˆœμ„œ (μ˜ˆμ‹œ): A → C → F → E → B → D
// (탐색 μˆœμ„œλŠ” μ΄μ›ƒμ˜ μΆ”κ°€ μˆœμ„œμ— 따라 λ‹¬λΌμ§ˆ 수 있음)

 

 

λ°˜μ‘ν˜•