--- 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 |