Ch.8 정렬과 탐색
Binary Search — 반씩 줄이는 탐색
100만 개 중에서 20번이면 찾는다?
사전에서 단어를 찾을 때 처음부터 넘기지 않습니다. 가운데를 펴고, 앞인지 뒤인지 판단합니다.
코드로 옮기면 경계값(lo, hi, mid) 처리가 항상 헷갈린다
불변식(invariant)을 유지하면 off-by-one 에러 없이 깔끔하게 구현할 수 있습니다.
핵심 개념
Binary Search
정렬된 배열에서 탐색 범위를 절반씩 줄이는 O(log n) 알고리즘
불변식(Invariant)
알고리즘 실행 중 항상 참인 조건
핵심 내용
정렬된 배열이라면 절반씩 줄일 수 있습니다
n = 1,000,000일 때 log₂(1,000,000) ≈ 20번 비교면 충분합니다
불변식: **target이 있다면 arr[lo..hi] 범위 안에 있다**
def binary_search(arr, target):
lo, hi = 0, len(arr) - 1
while lo <= hi: # 불변식: target ∈ arr[lo..hi]
mid = lo + (hi - lo) // 2 # 오버플로우 방지
if arr[mid] == target:
return mid
elif arr[mid] < target:
lo = mid + 1 # 왼쪽 절반 제거
else:
hi = mid - 1 # 오른쪽 절반 제거
return -1 # 찾지 못함`mid = lo + (hi - lo) // 2`는 (lo + hi) // 2와 같지만 오버플로우를 방지합니다
[1, 3, 5, 7, 9, 11]에서 target=7을 찾는 과정입니다
6개 원소에서 3번 만에 찾았습니다. 선형 탐색이면 4번이었을 것
Binary Search의 90%는 경계값 실수에서 버그가 발생합니다
흔한 실수 3가지: 1. `while lo < hi` vs `while lo <= hi` — 등호 빠뜨림 2. `mid = (lo + hi) // 2` — 큰 수에서 오버플로우 3. `lo = mid` — 무한 루프 발생 가능
# 재귀 버전
def binary_search_rec(arr, target, lo=0, hi=None):
if hi is None:
hi = len(arr) - 1
if lo > hi:
return -1
mid = lo + (hi - lo) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
return binary_search_rec(arr, target, mid + 1, hi)
else:
return binary_search_rec(arr, target, lo, mid - 1)면접에서는 반복문 버전을 권장합니다 — 재귀 스택 O(log n) 추가 공간 없음
Python은 Binary Search를 내장 모듈로 제공합니다
import bisect
arr = [1, 3, 5, 7, 9, 11]
# 삽입 위치 찾기 (왼쪽)
bisect.bisect_left(arr, 7) # → 3
# 삽입 위치 찾기 (오른쪽)
bisect.bisect_right(arr, 7) # → 4
# 원소 존재 확인
def bs_contains(arr, target):
i = bisect.bisect_left(arr, target)
return i < len(arr) and arr[i] == target면접에서 `bisect`를 쓸 수 있는지 먼저 확인하세요. 직접 구현을 요구하는 경우가 많습니다
길이 1024의 정렬된 배열에서 Binary Search로 최대 몇 번 비교하나요?
Binary Search는 정렬되지 않은 배열에도 사용할 수 있다
Binary Search 마스터!
핵심 용어
전제 조건
배열이 정렬되어 있어야 함
핵심 아이디어
mid값과 비교하여 탐색 범위를 절반으로
시간 복잡도
O(log n) — n=100만이면 20번
정리 노트
Binary Search — 기본
핵심 개념
- 전제
- 정렬된 배열 필수
- 시간
- O(log n) — n=100만이면 20번
- 불변식
- target ∈ arr[lo..hi]
구현 주의점
- while 조건
- `lo <= hi` — 등호 빠뜨리지 말 것
- mid 계산
- `lo + (hi - lo) // 2` — 오버플로우 방지
- Python
- `bisect.bisect_left/right` 활용 가능
Binary Search를 쓸 수 있으면 '정렬 먼저 하고 bisect' 패턴을 고려하세요!
시각 자료
핵심 정리
- 1정렬된 배열 + 절반씩 줄이기 = O(log n)
- 2불변식 유지로 경계값 실수 방지
- 3Python bisect 모듈로 간결하게 구현 가능
퀴즈와 인터랙션으로 더 깊이 학습하세요
play_circle인터랙티브 레슨 시작