f8b21af4be
10_Wiki/Topics 대규모 정리: - 오류 캡처/미완성 stub 문서 227개 제거 - 교차폴더 중복 43클러스터 병합 (63파일 → redirect) - 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건 - 카테고리 MOC 6개 신규 생성 - Graph 섹션 미해결 related-keyword 링크 10,058건 제거 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
228 lines
6.1 KiB
Markdown
228 lines
6.1 KiB
Markdown
---
|
|
id: wiki-2026-0508-binary-search
|
|
title: Binary Search
|
|
category: 10_Wiki/Topics
|
|
status: verified
|
|
canonical_id: self
|
|
aliases: [이진 탐색, bisect, divide and conquer search, lower bound, upper bound, git bisect]
|
|
duplicate_of: none
|
|
source_trust_level: A
|
|
confidence_score: 0.97
|
|
verification_status: applied
|
|
tags: [algorithm, search, divide-conquer, log-n, bisection, git-bisect, parametric-search]
|
|
raw_sources: []
|
|
last_reinforced: 2026-05-10
|
|
github_commit: pending
|
|
tech_stack:
|
|
language: any
|
|
framework: standard library
|
|
---
|
|
|
|
# Binary Search
|
|
|
|
## 📌 한 줄 통찰
|
|
> **"매 절반씩 의 탐색"**. 매 sorted array 의 매 O(log N). 매 100만 = 매 20 step. 매 algorithm 의 elegance 의 가장. 매 git bisect / parametric search / boundary find 의 same 원리.
|
|
|
|
## 📖 핵심
|
|
|
|
### 매 algorithm
|
|
1. 매 mid = (lo + hi) / 2.
|
|
2. 매 target == mid → return.
|
|
3. 매 target < mid → hi = mid - 1.
|
|
4. 매 target > mid → lo = mid + 1.
|
|
5. 매 lo > hi → not found.
|
|
|
|
### 매 complexity
|
|
- **Time**: O(log N). 매 100만 = 20 comparison.
|
|
- **Space**: O(1) iterative / O(log N) recursive.
|
|
- **Precondition**: 매 sorted (or monotonic predicate).
|
|
|
|
### 매 variant
|
|
|
|
#### Lower bound (first ≥ target)
|
|
- 매 첫 매 element ≥ target.
|
|
|
|
#### Upper bound (first > target)
|
|
- 매 첫 매 element > target.
|
|
|
|
#### Range [first, last]
|
|
- 매 lower / upper 의 결합.
|
|
|
|
#### Bisection on continuous
|
|
- 매 root finding (math).
|
|
- 매 epsilon-based termination.
|
|
|
|
#### Parametric search
|
|
- 매 monotonic predicate 의 boundary.
|
|
- 매 "최대 X 의 Y 의 OK" 의 search.
|
|
|
|
#### Galloping (exponential + binary)
|
|
- 매 unbounded 의 매 growing range 의 binary.
|
|
|
|
### 매 trap
|
|
- **Overflow**: `(lo + hi) / 2` 의 int overflow → `lo + (hi - lo) / 2`.
|
|
- **Off-by-one**: lo / hi / mid 의 boundary.
|
|
- **Infinite loop**: 매 mid 의 적절한 update.
|
|
- **Sorted assumption**: 매 unsorted 의 fail.
|
|
- **Float precision**: 매 epsilon 의 fix.
|
|
|
|
### 매 응용
|
|
1. **`bisect` module** (Python).
|
|
2. **`std::lower_bound`** (C++).
|
|
3. **DB index** (B-tree): 매 internal node search.
|
|
4. **`git bisect`**: 매 commit 의 first bad.
|
|
5. **Parametric** (LeetCode): "min capacity for delivery in D days".
|
|
6. **Hyperparameter tune**: 매 LR sweep.
|
|
7. **Quantile estimate**: 매 streaming.
|
|
|
|
### 매 modern variant
|
|
- **Branchless binary search**: 매 conditional move.
|
|
- **Eytzinger layout**: 매 cache-friendly.
|
|
- **Interpolation search**: 매 uniform 의 O(log log N).
|
|
- **Fractional cascading**: 매 multi-list.
|
|
|
|
## 💻 패턴
|
|
|
|
### Classic (iterative)
|
|
```python
|
|
def binary_search(arr, target):
|
|
lo, hi = 0, len(arr) - 1
|
|
while lo <= hi:
|
|
mid = lo + (hi - lo) // 2
|
|
if arr[mid] == target: return mid
|
|
if arr[mid] < target: lo = mid + 1
|
|
else: hi = mid - 1
|
|
return -1
|
|
```
|
|
|
|
### Lower bound (first ≥)
|
|
```python
|
|
def lower_bound(arr, target):
|
|
lo, hi = 0, len(arr)
|
|
while lo < hi:
|
|
mid = lo + (hi - lo) // 2
|
|
if arr[mid] < target: lo = mid + 1
|
|
else: hi = mid
|
|
return lo # 매 insertion point
|
|
```
|
|
|
|
### Python `bisect`
|
|
```python
|
|
import bisect
|
|
arr = [1, 3, 5, 7, 9]
|
|
bisect.bisect_left(arr, 5) # 2
|
|
bisect.bisect_right(arr, 5) # 3
|
|
bisect.insort(arr, 6) # 매 maintain sorted
|
|
```
|
|
|
|
### Parametric search ("min eat speed")
|
|
```python
|
|
def min_eating_speed(piles, h):
|
|
def can_eat(k):
|
|
return sum((p + k - 1) // k for p in piles) <= h
|
|
|
|
lo, hi = 1, max(piles)
|
|
while lo < hi:
|
|
mid = lo + (hi - lo) // 2
|
|
if can_eat(mid): hi = mid
|
|
else: lo = mid + 1
|
|
return lo
|
|
```
|
|
|
|
→ 매 monotonic predicate 의 boundary.
|
|
|
|
### Bisection on float (root)
|
|
```python
|
|
def find_root(f, lo, hi, eps=1e-9):
|
|
while hi - lo > eps:
|
|
mid = (lo + hi) / 2
|
|
if f(mid) * f(lo) < 0: hi = mid
|
|
else: lo = mid
|
|
return (lo + hi) / 2
|
|
|
|
# sqrt(2) 의 root of x² - 2 = 0
|
|
result = find_root(lambda x: x*x - 2, 0, 2)
|
|
# 1.414213562373...
|
|
```
|
|
|
|
### `git bisect` (CLI)
|
|
```bash
|
|
git bisect start
|
|
git bisect bad HEAD
|
|
git bisect good v1.0
|
|
# 매 매 step 의 매 commit 의 test
|
|
git bisect good # or 'bad'
|
|
# 매 log N step → 매 first bad commit
|
|
git bisect reset
|
|
```
|
|
|
|
→ 매 1000 commit 의 매 10 step 의 culprit 의 find.
|
|
|
|
### Galloping (exponential + binary)
|
|
```python
|
|
def galloping_search(arr, target):
|
|
if arr[0] == target: return 0
|
|
bound = 1
|
|
while bound < len(arr) and arr[bound] < target:
|
|
bound *= 2
|
|
lo = bound // 2
|
|
hi = min(bound, len(arr) - 1)
|
|
return binary_search_range(arr, target, lo, hi)
|
|
```
|
|
|
|
→ 매 unbounded / online stream 의 OK.
|
|
|
|
### Eytzinger layout (cache-friendly)
|
|
```python
|
|
def eytzinger_search(arr, target):
|
|
"""매 BFS layout — 매 cache miss 매 minimize."""
|
|
n = len(arr)
|
|
k = 1
|
|
while k <= n:
|
|
if arr[k-1] < target: k = 2*k + 1
|
|
elif arr[k-1] > target: k = 2*k
|
|
else: return k - 1
|
|
return -1
|
|
```
|
|
|
|
## 🤔 결정 기준
|
|
| 상황 | 사용 |
|
|
|---|---|
|
|
| Sorted array search | binary search |
|
|
| Sorted insert | bisect.insort |
|
|
| Predicate boundary | parametric search |
|
|
| Float root | bisection method |
|
|
| Commit debugging | git bisect |
|
|
| Streaming quantile | binary search + treap |
|
|
| Cache-critical | Eytzinger layout |
|
|
|
|
**기본값**: Python `bisect` / C++ `lower_bound` 사용. 매 직접 구현 X.
|
|
|
|
## 🔗 Graph
|
|
- 부모: [[Search]]
|
|
- 변형: [[Lower-Bound]] · [[Upper-Bound]]
|
|
- 응용: [[Git-Bisect]] · [[B-Tree]] · [[Sorting]]
|
|
|
|
## 🤖 LLM 활용
|
|
**언제**: 매 sorted data search. 매 monotonic boundary. 매 root finding. 매 commit debugging.
|
|
**언제 X**: 매 unsorted (sort 의 cost X). 매 small N (linear OK). 매 non-monotonic.
|
|
|
|
## ❌ 안티패턴
|
|
- **`(lo + hi) / 2` overflow**: 매 large array 의 fail.
|
|
- **Sorted assumption 위반**: 매 wrong result.
|
|
- **`while lo < hi` vs `<=` 의 confusion**: 매 off-by-one.
|
|
- **Float epsilon 무시**: 매 무한 loop.
|
|
- **Library 무시 + 직접 구현**: 매 bug.
|
|
- **Linear search 의 substitute (small N)**: 매 over-engineering.
|
|
|
|
## 🧪 검증 / 중복
|
|
- Verified (CLRS, Knuth TAOCP, classic).
|
|
- 신뢰도 A.
|
|
- Related: [[Sorting]] · [[Divide-and-Conquer]] · [[Git-Bisect]] · [[B-Tree]].
|
|
|
|
## 🕓 Changelog
|
|
| 날짜 | 변경 |
|
|
|---|---|
|
|
| 2026-05-08 | Phase 1 |
|
|
| 2026-05-10 | Manual cleanup — variant + parametric + 매 git bisect + 매 Eytzinger + code |
|