topic난이도 · 약 20

재귀 · 분할정복 — 자기 자신을 부르는 함수

탈출 조건 + 자기 호출. 트리 순회·머지 정렬·DP의 뼈대. 스택 오버플로 주의.

#재귀#분할정복#머지정렬#기저사례
왜 배우는가

JSON 구조 순회·디렉토리 탐색·DOM 탐색 — 전부 재귀가 자연스럽다. 탈출 조건이 빠지면 스택 오버플로(ch14-3). AI가 만든 재귀 코드가 맞는지 보는 눈.

재귀(Recursion)의 뼈대는 두 줄. ① 기저 사례(base case) — 멈추는 조건. ② 재귀 호출 — 문제를 작은 자신으로 축소. 기저가 없거나 잘못되면 무한 반복 → 스택 오버플로.

javascript
// 팩토리얼 — 가장 쉬운 예
function fact(n) {
  if (n <= 1) return 1;          // ① 기저
  return n * fact(n - 1);        // ② 재귀
}

// 트리·JSON 순회 (실전)
function walk(node, fn) {
  fn(node);
  for (const child of node.children ?? []) walk(child, fn);
}
walk(root, n => console.log(n.name));

// 파일 시스템 순회
async function listAll(dir) {
  const items = await fs.readdir(dir, { withFileTypes: true });
  for (const item of items) {
    const full = path.join(dir, item.name);
    if (item.isDirectory()) await listAll(full);   // 재귀
    else console.log(full);
  }
}

재귀가 어울리는 문제: 트리·JSON·디렉토리·수식·그래프 DFS. 반복문이 더 어울리는 문제: 평평한 배열·누적합.

분할정복(Divide & Conquer)은 재귀의 고급형. ① 나누고(divide) ② 각각 풀고(conquer) ③ 합친다(combine). 머지 정렬·퀵 정렬·이진 탐색의 공통 뼈대. Big O 분석이 마스터 정리(master theorem)로 체계화.

javascript
// 머지 정렬 — 분할정복 교과서
function mergeSort(arr) {
  if (arr.length <= 1) return arr;
  const mid = arr.length >> 1;
  const left  = mergeSort(arr.slice(0, mid));   // 나누기
  const right = mergeSort(arr.slice(mid));
  return merge(left, right);                    // 합치기
}
function merge(a, b) {
  const out = [];
  let i = 0, j = 0;
  while (i < a.length && j < b.length) {
    out.push(a[i] <= b[j] ? a[i++] : b[j++]);
  }
  return [...out, ...a.slice(i), ...b.slice(j)];
}
// O(n log n) — log n개 단계 × 각 단계 O(n) 합치기

머지·퀵 정렬, FFT, 크고 작은 배열 비교 — 분할정복 패턴 자체가 성능 돌파구.

재귀 최적화 2종.꼬리 재귀(tail call) — 마지막에 자기 호출만 하면 컴파일러가 반복문으로 치환 가능(JS는 엔진별 편차). ② 메모이제이션 — 같은 인자 재호출 결과를 캐시(ch18-4 DP). 재귀가 느리면 이 둘부터 본다.

실기 드릴 2문항
edit실기 드릴 · 단답형

재귀 함수에서 호출을 멈추는 조건을 가리키는 용어는?

check_circle실기 드릴 · OX

머지 정렬의 시간복잡도는 O(n²)이다.