topic난이도 · 약 25

선형 vs 이진 탐색 — log n이 왜 마법인가

정렬된 데이터에서 절반씩 잘라 찾기. DB 인덱스·Git·Up to Date 검색의 공통 원리.

#이진탐색#binary search#log n#bisect#Git bisect
왜 배우는가

데이터 100만 건에서 선형 탐색은 최악 100만 번, 이진 탐색은 20번이면 끝난다. 이 개념이 B-Tree 인덱스·Git bisect·Array.sort 이진 검색의 바탕. 해시맵과 함께 AI 코드를 빠르게 만드는 2대 무기.

이진 탐색은 '업다운 게임'이다. 1~100 중 숫자 맞히기 게임에서 "50?" → "너무 커" → "25?" → "너무 작아" → "37?" ... 매 질문마다 후보가 절반으로 준다. 100만 건도 이 방식이면 20번이면 끝난다(`log₂ 1,000,000 ≈ 20`).

탐색 비교 — 선형은 n번, 이진은 log n번. 100만 건 기준 100만 대 20
데이터 크기선형 탐색 (최악)이진 탐색 (최악)
1001007
10,00010,00014
1,000,0001,000,00020
10억10억30
전제조건없음정렬되어 있어야 함
javascript
// ❌ 선형 탐색 — O(n), 정렬 필요 없음
function linearSearch(arr, target) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === target) return i;
  }
  return -1;
}

// ✅ 이진 탐색 — O(log n), 반드시 정렬되어 있어야 함
function binarySearch(sortedArr, target) {
  let lo = 0, hi = sortedArr.length - 1;
  while (lo <= hi) {
    const mid = Math.floor((lo + hi) / 2);
    if (sortedArr[mid] === target) return mid;
    if (sortedArr[mid] < target) lo = mid + 1;
    else                          hi = mid - 1;
  }
  return -1;
}

// 실전: 정렬 + 이진 탐색 자동 내장 (JS는 메서드 없음, 파이썬·Go는 있음)
// Python:  import bisect;  bisect.bisect_left(sorted_list, target)
// Go:      sort.SearchInts(arr, target)

JS는 표준 이진탐색 메서드가 없어서 직접 쓰거나 lodash의 `sortedIndexOf`를 쓴다. 단 배열이 정렬돼 있지 않으면 결과가 엉망이 되므로 주의.

바이브코더가 매일 쓰는 이진 탐색들. 직접 구현할 일은 드물지만, 내부 원리를 알면 AI 코드·도구 동작이 투명해진다.

어디에이진 탐색을 어떻게효과
DB 인덱스 (B-Tree)정렬된 트리를 내려가며 탐색100만 행에서 0.001초
Git bisect커밋 히스토리 이분하여 버그 커밋 찾기1000 커밋을 10번으로
파일 시스템 (정렬된 디렉토리)readdir 결과를 이진 탐색`find`가 빠른 이유
자동완성·사전정렬된 단어 사전에서 prefix 이분즉시 제안
k번째 원소, 범위 쿼리이진 탐색 변형 (lower_bound)정렬 + O(log n)
bash
# Git bisect — 1000개 커밋 중 버그 심은 커밋 찾기
# 선형이면 1000개 commit checkout, 이진이면 log₂(1000) ≈ 10번

git bisect start
git bisect bad               # 현재 (버그 있음)
git bisect good v1.0         # v1.0 시점은 정상

# Git이 자동으로 중간 커밋으로 이동
# 테스트 후:
git bisect good   # 또는 bad
# → 계속 절반씩 범위를 좁힘

git bisect reset  # 종료

"언제부터 망가졌지?" 디버깅 상황의 최강 무기. 이진 탐색의 실전 예시.

이진 탐색의 변형 두 가지를 알면 실전에서 90% 상황이 커버된다. `lower_bound(x)` = `x 이상인 첫 번째 위치`, `upper_bound(x)` = `x보다 큰 첫 번째 위치`. 이 둘로 범위 카운팅정렬 유지 삽입이 모두 가능하다.

대규모 점수 랭킹·타임라인 조회에서 선형으로 세면 1초, bisect로는 즉시. JS는 `lodash.sortedIndex`로 유사 기능.

치명적 함정.정렬되지 않은 배열에 이진 탐색 쓰면 결과가 완전 엉망이 된다 — 실패도 아니고 오답이 나옴. ② `mid = (lo + hi) / 2`는 큰 수에서 정수 오버플로 위험 → `lo + (hi - lo) / 2`가 안전. ③ 실수(float)에서는 `==` 비교 금지 → 부동소수점 오차(ch16-3 참고).

상황해시맵 (O(1))이진 탐색 (O(log n))
정확한 키로 단건 조회✅ 더 빠름✅ 되지만 느림
범위 검색 (60~80점)❌ 순서 없음✅ 완벽
k번째 원소
근사 검색 (가장 가까운 값)
정렬 순회
추가/삭제O(1)O(n) (배열이면)

해시맵과 이진탐색은 경쟁이 아니라 파트너. 단건 조회는 해시맵, 범위·근사·k번째는 이진탐색. DB는 이 두 가지를 인덱스(B-Tree = 이진탐색)와 해시 인덱스로 제공한다(ch22-3에서 이어짐).

Claude에게 이렇게 말하면 바로 고쳐준다. "이 정렬된 리스트에서 매번 `indexOf`로 찾는 구간이 있어. 이진 탐색(`bisect_left` 또는 JS 구현)으로 바꿔서 O(log n)으로 만들어줘." — '정렬됨'을 명시하는 게 핵심. Claude가 확신을 갖고 구현한다.

한 줄 요약: 정렬된 데이터 + 이분 질문 = O(log n). 100만 건 데이터 조회를 0.02초로. 단건은 해시맵, 범위·근사·순서는 이진탐색. Git bisect·DB 인덱스·자동완성 전부 이 원리.

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

정렬된 1,000,000개 원소에서 이진 탐색은 최악 몇 번 비교로 찾는가?

check_circle실기 드릴 · OX

이진 탐색은 정렬되지 않은 배열에도 쓸 수 있다.

edit실기 드릴 · 단답형

Git에서 '언제부터 버그가 생겼는지'를 이진 탐색으로 찾는 명령은?

check_circle실기 드릴 · OX

단건 조회라면 해시맵이 이진 탐색보다 평균적으로 빠르다.