포슀트

CS β€” find vs binary search

CS β€” find vs binary search

πŸ“• 05/05 β€” std::find vs std::binary_search (μ„ ν˜• 탐색 vs 이뢄 탐색)

λͺ¨μ˜λ©΄μ ‘ 주제: β€œstd::find()와 std::binary_search()의 차이점에 λŒ€ν•΄μ„œ μ„€λͺ…ν•΄ μ£Όμ„Έμš”β€ μ •λ ¬ μ „μ œ β†’ μ‹œκ°„λ³΅μž‘λ„ β†’ λ°˜ν™˜ νƒ€μž… 차이 β†’ lower_boundΒ·equal_range β†’ set/map 멀버 ν•¨μˆ˜ vs μ•Œκ³ λ¦¬μ¦˜ 꼬리질문 μ—°κ²° 닀리


ν•™μŠ΅ μ˜μ—­ μ „ν™˜μ  β€” μ»¨ν…Œμ΄λ„ˆμ—μ„œ μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ

13~16λ²ˆμ—μ„œ STL μ»¨ν…Œμ΄λ„ˆ μ „λ°˜(μ‹œν€€μŠ€Β·μ—°κ΄€Β·λΉ„μˆœμ„œΒ·μ–΄λŒ‘ν„°)을 μ •λ¦¬ν–ˆλ‹€λ©΄, 17λ²ˆλΆ€ν„°λŠ” κ·Έ μœ„μ—μ„œ λ™μž‘ν•˜λŠ” <algorithm> ν—€λ”μ˜ 탐색 ν•¨μˆ˜λ₯Ό λ‹€λ£Ήλ‹ˆλ‹€.

1
2
3
4
13~16번  STL μ»¨ν…Œμ΄λ„ˆ                       β€” 자료ꡬ쑰 (어디에 λ‹΄μ„κΉŒ)
─────────────────────────────────────────────────────────────────────
17번  std::find vs std::binary_search β˜…    β€” μ•Œκ³ λ¦¬μ¦˜ (μ–΄λ–»κ²Œ μ°Ύμ„κΉŒ)
이후    sort / lower_bound / equal_range   β€” μ •λ ¬Β·λ²”μœ„ μ•Œκ³ λ¦¬μ¦˜ family

이 μ£Όμ œλŠ” λ©΄μ ‘μ—μ„œ β€œλ‘ ν•¨μˆ˜μ˜ μ°¨μ΄λŠ”?” μ‹μœΌλ‘œ 쒁게 듀어와도 κ²°κ΅­ (1) μ •λ ¬ μ „μ œ β†’ (2) μ‹œκ°„λ³΅μž‘λ„ β†’ (3) λ°˜ν™˜ νƒ€μž… 차이 β†’ (4) 더 λ‚˜μ€ λŒ€μ•ˆ(lower_bound) β†’ (5) set/map 멀버 ν•¨μˆ˜μ™€μ˜ λΉ„κ΅λ‘œ νŽΌμ³μ§‘λ‹ˆλ‹€. λ‹¨μˆœνžˆ β€œμ„ ν˜• vs μ΄λΆ„β€μ΄λΌκ³ λ§Œ λ‹΅ν•˜λ©΄ κΌ¬λ¦¬μ§ˆλ¬Έμ—μ„œ λ§‰νž™λ‹ˆλ‹€.


λͺ¨μ˜λ©΄μ ‘ λ‹΅λ³€

std::find와 std::binary_searchλŠ” λ‘˜ λ‹€ <algorithm> ν—€λ”μ˜ 탐색 ν•¨μˆ˜μ§€λ§Œ μ „μ œ 쑰건과 μ‹œκ°„λ³΅μž‘λ„, λ°˜ν™˜ νƒ€μž…μ΄ λͺ¨λ‘ λ‹€λ¦…λ‹ˆλ‹€.

std::findλŠ” μ„ ν˜• νƒμƒ‰μž…λ‹ˆλ‹€. [first, last) ꡬ간을 μ²˜μŒλΆ€ν„° λκΉŒμ§€ μˆœνšŒν•˜λ©΄μ„œ == μ—°μ‚°μžλ‘œ 값을 λΉ„κ΅ν•˜κ³ , μΌμΉ˜ν•˜λŠ” 첫 μ›μ†Œμ˜ iteratorλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. λͺ» 찾으면 lastλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. μ‹œκ°„λ³΅μž‘λ„λŠ” O(n)이고 μ»¨ν…Œμ΄λ„ˆκ°€ 정렬돼 μžˆμ„ ν•„μš”κ°€ μ—†μœΌλ©°, vectorΒ·listΒ·deque λ“± μ–΄λ–€ μ‹œν€€μŠ€μ—λ„ μ“Έ 수 μžˆμŠ΅λ‹ˆλ‹€.

std::binary_searchλŠ” 이진 νƒμƒ‰μž…λ‹ˆλ‹€. O(log n)으둜 λΉ λ₯Έ λŒ€μ‹  사전 정렬이 ν•„μˆ˜ μ „μ œμž…λ‹ˆλ‹€. 또 비ꡐ 방식이 ==이 μ•„λ‹ˆλΌ < μ—°μ‚°μž 두 번으둜 λ™μΉ˜λ₯Ό νŒλ‹¨ν•©λ‹ˆλ‹€ β€” !(a < b) && !(b < a)이면 κ°™λ‹€κ³  λ΄…λ‹ˆλ‹€. 결정적인 μ°¨μ΄λŠ” λ°˜ν™˜ νƒ€μž…μ΄ bool ν•˜λ‚˜λΏμ΄λΌλŠ” μ μž…λ‹ˆλ‹€. β€œμžˆλƒ/μ—†λƒβ€λ§Œ μ•Œλ €μ£Όκ³  μœ„μΉ˜λŠ” μ•ˆ μ•Œλ €μ€λ‹ˆλ‹€. κ·Έλž˜μ„œ μœ„μΉ˜κΉŒμ§€ ν•„μš”ν•˜λ©΄ 보톡 std::lower_boundλ‚˜ std::equal_rangeλ₯Ό μ”λ‹ˆλ‹€. 사싀 binary_search λ‚΄λΆ€ κ΅¬ν˜„ μžμ²΄κ°€ lower_bound 호좜이고, μ •λ ¬λ˜μ§€ μ•Šμ€ μ»¨ν…Œμ΄λ„ˆμ— μ‚¬μš©ν•˜λ©΄ κ²°κ³ΌλŠ” λ―Έμ •μ˜ λ™μž‘(UB)μž…λ‹ˆλ‹€.

선택 기쀀은 λ‹¨μˆœν•©λ‹ˆλ‹€. 정렬돼 있고 μœ„μΉ˜κ°€ ν•„μš” μ—†μœΌλ©΄ binary_search, μœ„μΉ˜ iteratorκ°€ ν•„μš”ν•˜λ©΄ lower_bound, 정렬돼 μžˆμ§€ μ•Šκ±°λ‚˜ μΌνšŒμ„±μ΄λ©΄ find. 그리고 자료ꡬ쑰 μžμ²΄κ°€ 트리/ν•΄μ‹œμΈ std::setΒ·std::mapΒ·std::unordered_mapμ—μ„œλŠ” μ•Œκ³ λ¦¬μ¦˜ ν•¨μˆ˜ λŒ€μ‹  멀버 ν•¨μˆ˜ find()λ₯Ό 써야 ν•©λ‹ˆλ‹€ β€” μ•Œκ³ λ¦¬μ¦˜ ν•¨μˆ˜λŠ” μ»¨ν…Œμ΄λ„ˆ λ‚΄λΆ€ ꡬ쑰λ₯Ό λ¬΄μ‹œν•˜κ³  O(n)으둜 λ„λŠ” 반면, 멀버 ν•¨μˆ˜λŠ” νŠΈλ¦¬λŠ” O(log n), ν•΄μ‹œλŠ” 평균 O(1)을 보μž₯ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.


핡심 κ°œλ…

λΆ„λ₯˜ν‚€μ›Œλ“œν•œ 쀄 μ •μ˜
μ •μ˜std::findμ„ ν˜• 탐색. [first, last) 순회, ==둜 비ꡐ, iterator λ°˜ν™˜
Β std::binary_search이뢄 탐색. μ •λ ¬ ν•„μˆ˜, <둜 비ꡐ, bool λ°˜ν™˜
헀더<algorithm>두 ν•¨μˆ˜ λͺ¨λ‘ 같은 헀더에 μ •μ˜
μ‹œκ°„λ³΅μž‘λ„O(n) μ„ ν˜•find β€” μ΅œμ•… n번 비ꡐ
Β O(log n) 이뢄binary_search β€” μ΅œμ•… logβ‚‚(n)+1 번 비ꡐ
λ°˜ν™˜ νƒ€μž…iteratorfind β€” μœ„μΉ˜ 정보 (λͺ» 찾으면 last)
Β boolbinary_search β€” 쑴재 μ—¬λΆ€λ§Œ
비ꡐ μ—°μ‚°μž==find β€” equality 비ꡐ
Β < 두 번binary_search β€” !(a<b) && !(b<a) λ™μΉ˜ νŒλ‹¨
μ „μ œμ •λ ¬ λΆˆν•„μš”find
 사전 μ •λ ¬ ν•„μˆ˜binary_search β€” μ•ˆ 되면 UB
Β Random Access ꢌμž₯binary_searchλŠ” list에 써도 λ™μž‘μ€ ν•˜μ§€λ§Œ O(n) 거리 계산이 듀어감
κ΄€λ ¨ ν•¨μˆ˜std::lower_boundμ •λ ¬ κ΅¬κ°„μ—μ„œ value 이상 첫 μœ„μΉ˜ iterator λ°˜ν™˜. binary_search λ‚΄λΆ€ κ΅¬ν˜„
Β std::upper_boundμ •λ ¬ κ΅¬κ°„μ—μ„œ value 초과 첫 μœ„μΉ˜ iterator λ°˜ν™˜
Β std::equal_range{lower_bound, upper_bound} 쌍 λ°˜ν™˜. 동일 ν‚€ λ²”μœ„
멀버 vs μ•Œκ³ λ¦¬μ¦˜set/map::findRB-Tree O(log n) 멀버 ν•¨μˆ˜ β€” λ°˜λ“œμ‹œ 이걸 씀
Β unordered_map::findν•΄μ‹œ 평균 O(1) 멀버 ν•¨μˆ˜
Β μ•Œκ³ λ¦¬μ¦˜ std::findμ»¨ν…Œμ΄λ„ˆ ꡬ쑰 λ¬΄μ‹œ O(n) β€” μ—°κ΄€ μ»¨ν…Œμ΄λ„ˆμ— μ“°λ©΄ 손해
함정정렬 μ•ˆ 된 μ»¨ν…Œμ΄λ„ˆ + binary_searchλ―Έμ •μ˜ λ™μž‘ (UB)
Β strict weak ordering κΉ¨μ§λΉ„κ΅μžκ°€ 잘λͺ»λ˜λ©΄ binary_search κ²°κ³Ό 보μž₯ μ•ˆ 됨
언리얼Algo::Findstd::find λŒ€μ‘ (μ„ ν˜•)
Β Algo::BinarySearchstd::binary_search λŒ€μ‘. int32 인덱슀 λ°˜ν™˜ (INDEX_NONE = -1)
Β TArray::Find멀버 ν•¨μˆ˜. 인덱슀 λ°˜ν™˜

λͺ©μ°¨

  1. 핡심 μš”μ•½ μΉ΄λ“œ
  2. std::find β€” μ„ ν˜• 탐색
  3. std::binary_search β€” 이뢄 탐색
  4. 핡심 차이점 5κ°€μ§€
  5. κ΄€λ ¨ μ•Œκ³ λ¦¬μ¦˜ family β€” lower_bound / upper_bound / equal_range
  6. μ½”λ“œ 비ꡐ β€” vector 기반
  7. 꼬리질문 μ˜ˆμƒ 경둜
  8. μ–Έλ¦¬μ–Όμ—μ„œμ˜ 탐색 β€” Algo::Find / Algo::BinarySearch
  9. 보강 β€” iterator Β· λ™μΉ˜νŒλ‹¨ Β· lower_bound vs find
  10. 보강 β€” 큰 λ°μ΄ν„°μ—μ„œ find vs binary_search 선택

1. 핡심 μš”μ•½ μΉ΄λ“œ

30초 λ‹΅λ³€

1
2
3
4
5
std::find          = μ„ ν˜• 탐색, O(n), iterator λ°˜ν™˜, μ •λ ¬ λΆˆν•„μš”, == 비ꡐ
std::binary_search = 이뢄 탐색, O(log n), bool λ°˜ν™˜, μ •λ ¬ ν•„μˆ˜, < 비ꡐ

μœ„μΉ˜κΉŒμ§€ ν•„μš”ν•˜λ©΄ β†’ std::lower_bound (binary_search λ‚΄λΆ€ κ΅¬ν˜„)
set/map/unordered_map β†’ 멀버 ν•¨μˆ˜ find() μ‚¬μš© (μ•Œκ³ λ¦¬μ¦˜ X)

꼬리질문 μ—°κ²° λ§΅

1
2
3
4
5
6
7
8
9
std::find vs binary_search
β”œβ”€β”€ μ™œ binary_searchλŠ” bool만? β†’ lower_boundκ°€ μœ„μΉ˜ λ‹΄λ‹Ή, λΆ„μ—… 섀계
β”œβ”€β”€ μ •λ ¬ μ•ˆ λλŠ”λ° binary_search? β†’ UB (Undefined Behavior)
β”œβ”€β”€ lower_bound vs upper_bound vs equal_range β†’ μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜ family
β”œβ”€β”€ set/mapμ—μ„œλŠ”? β†’ 멀버 ν•¨μˆ˜ find() (O(log n) / O(1) 보μž₯)
β”‚   └── μ™œ μ•Œκ³ λ¦¬μ¦˜ std::findλŠ” 손해? β†’ μ»¨ν…Œμ΄λ„ˆ λ‚΄λΆ€ ꡬ쑰 λ¬΄μ‹œ β†’ O(n)
β”œβ”€β”€ < 두 번으둜 λ™μΉ˜? β†’ strict weak ordering, == μ—°μ‚°μž 없어도 됨
└── list에 binary_search? β†’ λ™μž‘μ€ 함. 단 거리 계산 O(n) β†’ 의미 μ—†μŒ
    └── Random Access Iterator vs Forward Iterator

2. std::find β€” μ„ ν˜• 탐색

핡심 ν•œ λ¬Έμž₯

std::findλŠ” [first, last) ꡬ간을 μ²˜μŒλΆ€ν„° μˆœνšŒν•˜λ©° == μ—°μ‚°μžλ‘œ 값을 비ꡐ해, μΌμΉ˜ν•˜λŠ” 첫 μ›μ†Œμ˜ iteratorλ₯Ό λ°˜ν™˜ν•˜λŠ” μ„ ν˜• νƒμƒ‰μž…λ‹ˆλ‹€.

μ‹œκ·Έλ‹ˆμ²˜

1
2
3
4
#include <algorithm>

template <class InputIt, class T>
InputIt find(InputIt first, InputIt last, const T& value);
  • 헀더: <algorithm>
  • λ°˜ν™˜: value와 μΌμΉ˜ν•˜λŠ” 첫 iterator. λͺ» 찾으면 last
  • μ‹œκ°„λ³΅μž‘λ„: μ΅œμ•… O(n), μ΅œμ„  O(1) (첫 μ›μ†Œκ°€ 일치)
  • μš”κ΅¬ iterator: InputIterator (κ°€μž₯ μ•½ν•œ μš”κ΅¬μ‚¬ν•­ β€” forward_list, istream_iterator 등도 κ°€λŠ₯)
  • 비ꡐ 방식: *it == value (equality)

μ‚¬μš© μ˜ˆμ‹œ

1
2
3
4
5
6
7
std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
auto it = std::find(v.begin(), v.end(), 5);
if (it != v.end()) {
    std::cout << "찾음! 인덱슀: " << std::distance(v.begin(), it) << "\n";
} else {
    std::cout << "μ—†μŒ\n";
}

λ³€ν˜•

  • std::find_if β€” μˆ μ–΄(predicate) 기반. == λŒ€μ‹  λžŒλ‹€λ‘œ 쑰건 μ§€μ •
  • std::find_if_not β€” 쑰건을 λ§Œμ‘±ν•˜μ§€ μ•ŠλŠ” 첫 μ›μ†Œ
1
auto it = std::find_if(v.begin(), v.end(), [](int x){ return x > 4; });

3. std::binary_search β€” 이뢄 탐색

핡심 ν•œ λ¬Έμž₯

std::binary_searchλŠ” μ •λ ¬λœ κ΅¬κ°„μ—μ„œ < μ—°μ‚°μž 두 번으둜 λ™μΉ˜λ₯Ό νŒλ‹¨ν•˜λ©° 이뢄 νƒμƒ‰μœΌλ‘œ κ°’μ˜ 쑴재 μ—¬λΆ€λ§Œ 확인해, bool 만 λ°˜ν™˜ν•©λ‹ˆλ‹€.

μ‹œκ·Έλ‹ˆμ²˜

1
2
3
4
5
6
7
8
#include <algorithm>

template <class ForwardIt, class T>
bool binary_search(ForwardIt first, ForwardIt last, const T& value);

// λΉ„κ΅μž 버전
template <class ForwardIt, class T, class Compare>
bool binary_search(ForwardIt first, ForwardIt last, const T& value, Compare comp);
  • 헀더: <algorithm>
  • λ°˜ν™˜: bool β€” 있으면 true, μ—†μœΌλ©΄ false. μœ„μΉ˜λŠ” λͺ¨λ¦„
  • μ‹œκ°„λ³΅μž‘λ„: O(log n) 비ꡐ 횟수. 단 RandomAccessIteratorκ°€ μ•„λ‹ˆλ©΄ 거리 계산이 O(n)이 듀어감
  • μš”κ΅¬ iterator: ForwardIterator 이상 (μ‹€νš¨λŠ” RandomAccessIterator)
  • 비ꡐ 방식: !(a < b) && !(b < a) β€” < 두 번으둜 λ™μΉ˜ νŒλ‹¨

μ‚¬μš© μ˜ˆμ‹œ

1
2
3
4
5
6
7
8
9
std::vector<int> v = {1, 1, 2, 3, 4, 5, 6, 9};  // β˜… λ°˜λ“œμ‹œ μ •λ ¬
bool found = std::binary_search(v.begin(), v.end(), 5);
std::cout << (found ? "있음" : "μ—†μŒ") << "\n";  // 있음

// μœ„μΉ˜κΉŒμ§€ μ•Œκ³  μ‹Άλ‹€λ©΄ β†’ lower_bound
auto it = std::lower_bound(v.begin(), v.end(), 5);
if (it != v.end() && *it == 5) {
    std::cout << "μœ„μΉ˜: " << std::distance(v.begin(), it) << "\n";
}

함정

  • μ •λ ¬ μ•ˆ 된 μ»¨ν…Œμ΄λ„ˆ: κ²°κ³Ό 보μž₯ X β†’ Undefined Behavior
  • == μ—°μ‚°μžλ§Œ μ •μ˜λœ νƒ€μž…: μ»΄νŒŒμΌμ€ λ˜μ§€λ§Œ μ˜λ―Έκ°€ 깨짐. < λΉ„κ΅μžκ°€ strict weak ordering을 λ§Œμ‘±ν•΄μ•Ό 함
  • std::list에 μ‚¬μš©: λ™μž‘μ€ ν•˜μ§€λ§Œ 거리 계산이 O(n) β†’ 의미 μ—†μŒ

4. 핡심 차이점 5κ°€μ§€

ν•­λͺ©std::findstd::binary_search
μ•Œκ³ λ¦¬μ¦˜μ„ ν˜• 탐색이뢄 탐색
μ‹œκ°„λ³΅μž‘λ„O(n)O(log n) (비ꡐ 횟수 κΈ°μ€€)
사전 μ •λ ¬λΆˆν•„μš”ν•„μˆ˜ (μ•ˆ 되면 UB)
λ°˜ν™˜ νƒ€μž…Iterator (μœ„μΉ˜)bool (쑴재 μ—¬λΆ€λ§Œ)
비ꡐ μ—°μ‚°μž== (equality)< 두 번 (strict weak ordering)
μš”κ΅¬ iteratorInputIteratorForwardIterator (μ‹€νš¨λŠ” RandomAccess)
적용 μ»¨ν…Œμ΄λ„ˆvector, list, deque, forward_list, λͺ¨λ“  μ‹œν€€μŠ€μ •λ ¬λœ vector, deque, array (RandomAccess ꢌμž₯)
μ‚¬μš© μ‹œμ μ •λ ¬ μ•ˆ 됨 / μΌνšŒμ„± / μœ„μΉ˜ ν•„μš”μ •λ ¬ 자료 / λ‹€νšŒ 쑰회 / 쑴재만 확인
함정n 크면 λŠλ¦Όμ •λ ¬ μ•ˆ 되면 UB

μ™œ 이런 차이가 μƒκ²Όλ‚˜

  • find λŠ” κ°€μž₯ 일반적인 탐색 β€” μ–΄λ–€ iteratorλ“  λ°›κ³  μ–΄λ–€ μ»¨ν…Œμ΄λ„ˆλ“  λ°›κΈ° μœ„ν•΄ μ„ ν˜•μœΌλ‘œ 섀계됨. μœ„μΉ˜ 정보가 핡심이라 iterator λ°˜ν™˜.
  • binary_search λŠ” μ •λ ¬ μžλ£Œμ— νŠΉν™”λœ λΉ λ₯Έ 쑰회 β€” μœ„μΉ˜ μ±…μž„μ€ λΆ„λ¦¬ν•΄μ„œ lower_bound κ°€ 가져감. κ·Έλž˜μ„œ binary_searchλŠ” λ‹¨μˆœνžˆ bool만 λ°˜ν™˜.
  • 이게 STL의 λΆ„μ—… 섀계 μ² ν•™: 쑴재 확인은 binary_search, μœ„μΉ˜ 확인은 lower_bound, λ²”μœ„ 확인은 equal_range.

5. κ΄€λ ¨ μ•Œκ³ λ¦¬μ¦˜ family β€” lower_bound / upper_bound / equal_range

핡심 ν•œ λ¬Έμž₯

binary_search λ‚΄λΆ€λŠ” lower_bound 호좜이고, μœ„μΉ˜Β·λ²”μœ„κ°€ ν•„μš”ν•˜λ©΄ lower_boundΒ·upper_boundΒ·equal_range 셋이 μ •λ ¬ 자료 νƒμƒ‰μ˜ μ§„μ§œ λ„κ΅¬μž…λ‹ˆλ‹€.

μ‹œκ·Έλ‹ˆμ²˜

1
2
3
4
5
6
7
8
9
10
11
template <class ForwardIt, class T>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value);
// value 이상인 첫 μœ„μΉ˜

template <class ForwardIt, class T>
ForwardIt upper_bound(ForwardIt first, ForwardIt last, const T& value);
// value 초과인 첫 μœ„μΉ˜

template <class ForwardIt, class T>
std::pair<ForwardIt, ForwardIt> equal_range(ForwardIt first, ForwardIt last, const T& value);
// {lower_bound, upper_bound} 쌍 β†’ value와 같은 μ›μ†Œλ“€μ˜ λ²”μœ„

binary_search λ‚΄λΆ€ κ΅¬ν˜„ (κ°œλ…)

1
2
3
4
5
template <class It, class T>
bool binary_search(It first, It last, const T& value) {
    auto it = std::lower_bound(first, last, value);
    return it != last && !(value < *it);  // <만 μ‚¬μš© (==은 μ•ˆ 씀)
}

β†’ binary_searchλŠ” lower_bound + λ™μΉ˜ 검사 ν•œ μ€„μ§œλ¦¬ wrapperμž…λ‹ˆλ‹€. β†’ 이걸 μ•Œλ©΄ β€œμ™œ binary_searchλŠ” iterator μ•ˆ 돌렀쀘?β€μ˜ 닡이 λͺ…ν™•ν•΄μ§‘λ‹ˆλ‹€ β€” lower_boundκ°€ 이미 κ·Έ μ—­ν• .

비ꡐ ν‘œ

ν•¨μˆ˜λ°˜ν™˜μš©λ„λΉ„κ³ 
binary_searchbool쑴재 μ—¬λΆ€λ§Œλ‚΄λΆ€λŠ” lower_bound
lower_bounditeratorvalue 이상 첫 μœ„μΉ˜μ‚½μž… μœ„μΉ˜ 결정에도 μ‚¬μš©
upper_bounditeratorvalue 초과 첫 μœ„μΉ˜lower_bound와 쌍
equal_rangepair<It, It>같은 κ°’λ“€μ˜ λ²”μœ„multiset/multimapμ—μ„œ 자주

μ •λ ¬ μ»¨ν…Œμ΄λ„ˆμ—μ„œ multi ν‚€ λ‹€λ£° λ•Œ

1
2
3
std::vector<int> v = {1, 2, 2, 2, 3, 4};  // μ •λ ¬ + 쀑볡
auto [lo, hi] = std::equal_range(v.begin(), v.end(), 2);
std::cout << "2의 개수: " << std::distance(lo, hi) << "\n";  // 3

6. μ½”λ“œ 비ꡐ β€” vector 기반

find μ‚¬μš©

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};  // μ •λ ¬ X
    
    // μ„ ν˜• 탐색 β€” μ–΄λ–€ μˆœμ„œλ“  OK
    auto it = std::find(v.begin(), v.end(), 5);
    if (it != v.end()) {
        std::cout << "find: μœ„μΉ˜ " << std::distance(v.begin(), it)
                  << ", κ°’ " << *it << "\n";
    }
    // 좜λ ₯: find: μœ„μΉ˜ 4, κ°’ 5
}

binary_search μ‚¬μš©

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
    std::sort(v.begin(), v.end());  // β˜… 사전 μ •λ ¬ ν•„μˆ˜
    // v = {1, 1, 2, 3, 4, 5, 6, 9}
    
    bool found = std::binary_search(v.begin(), v.end(), 5);
    std::cout << "binary_search: " << (found ? "있음" : "μ—†μŒ") << "\n";
    // 좜λ ₯: binary_search: 있음
    
    // μœ„μΉ˜κΉŒμ§€ ν•„μš”ν•˜λ©΄ lower_bound
    auto it = std::lower_bound(v.begin(), v.end(), 5);
    if (it != v.end() && *it == 5) {
        std::cout << "lower_bound: μœ„μΉ˜ " << std::distance(v.begin(), it) << "\n";
    }
    // 좜λ ₯: lower_bound: μœ„μΉ˜ 5
}

μ„±λŠ₯ 차이 체감 (n = 1,000,000)

1
2
μ •λ ¬ μ•ˆ 함 + std::find       β†’ 평균 ~500,000 비ꡐ (O(n))
μ •λ ¬ 1회 (O(n log n)) + std::binary_search 100만 번 β†’ μ•½ 20 비ꡐ Γ— 100만

β†’ λ‹€νšŒ 쑰회면 μ •λ ¬ + binary_searchκ°€ 압도적, μΌνšŒμ„±μ΄λ©΄ findκ°€ λ‹¨μˆœν•˜κ³  빠름.


7. 꼬리질문 μ˜ˆμƒ 경둜

Q1. β€œμ™œ binary_searchλŠ” iteratorλ₯Ό μ•ˆ λŒλ €μ£Όλ‚˜μš”?”

STL은 μ±…μž„μ„ λΆ„λ¦¬ν•΄μ„œ μ„€κ³„ν–ˆμŠ΅λ‹ˆλ‹€. 쑴재 μ—¬λΆ€λ§Œ ν™•μΈν•˜λŠ” λΉ λ₯Έ κ²½λ‘œλŠ” binary_search(bool), μœ„μΉ˜κΉŒμ§€ μ•Œκ³  μ‹ΆμœΌλ©΄ lower_bound(iterator), 같은 κ°’λ“€μ˜ λ²”μœ„λŠ” equal_range(pair). 사싀 binary_search λ‚΄λΆ€ κ΅¬ν˜„ μžμ²΄κ°€ lower_boundλ₯Ό ν˜ΈμΆœν•œ λ’€ !(value < *it) ν•œ μ€„λ‘œ λ™μΉ˜ κ²€μ‚¬λ§Œ ν•˜λŠ” wrapperμž…λ‹ˆλ‹€. μœ„μΉ˜κ°€ ν•„μš”ν•˜λ©΄ lower_boundλ₯Ό 직접 λΆ€λ₯΄λŠ” 게 더 νš¨μœ¨μ μ΄μ—μš”.

Q2. β€œμ •λ ¬ μ•ˆ 된 μ»¨ν…Œμ΄λ„ˆμ— binary_search μ“°λ©΄ μ–΄λ–»κ²Œ λ˜λ‚˜μš”?”

Undefined Behaviorμž…λ‹ˆλ‹€. ν‘œμ€€μ€ β€œμ •λ ¬λΌ μžˆλ‹€β€λ₯Ό μ „μ œλ‘œλ§Œ λ™μž‘μ„ 보μž₯ν•©λ‹ˆλ‹€. 운이 μ’‹μœΌλ©΄ μš°μ—°νžˆ λ§žμ„ μˆ˜λ„ μžˆμ§€λ§Œ μΌλ°˜μ μœΌλ‘œλŠ” 잘λͺ»λœ κ²°κ³Ό λ˜λŠ” λ¬΄ν•œ λΆ„ν• λ‘œ λλ‚˜μ§€ μ•Šμ„ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ binary_search 호좜 전에 λ°˜λ“œμ‹œ std::is_sorted둜 κ²€μ¦ν•˜κ±°λ‚˜ std::sort둜 μ •λ ¬ν•΄μ•Ό ν•©λ‹ˆλ‹€.

Q3. β€œsetμ΄λ‚˜ mapμ—μ„œλŠ” 멀버 ν•¨μˆ˜ find와 μ•Œκ³ λ¦¬μ¦˜ std::find 쀑 뭘 써야 ν•˜λ‚˜μš”?”

λ°˜λ“œμ‹œ 멀버 ν•¨μˆ˜ find() μž…λ‹ˆλ‹€. std::set::findλŠ” RB-Treeλ₯Ό 타고 O(log n), std::unordered_map::findλŠ” ν•΄μ‹œ 버킷 ν•œ 번 쑰회둜 평균 O(1)을 보μž₯ν•©λ‹ˆλ‹€. 반면 μ•Œκ³ λ¦¬μ¦˜ std::findλŠ” μ»¨ν…Œμ΄λ„ˆ λ‚΄λΆ€ ꡬ쑰λ₯Ό λͺ¨λ₯΄κ³  κ·Έλƒ₯ iteratorλ₯Ό μ²˜μŒλΆ€ν„° λκΉŒμ§€ λ„λŠ” O(n) μ„ ν˜• νƒμƒ‰μž…λ‹ˆλ‹€. 자료ꡬ쑰의 μž₯점을 ν†΅μ§Έλ‘œ λ²„λ¦¬λŠ” μ…ˆμ΄λΌ μ ˆλŒ€ μ•ˆ μ”λ‹ˆλ‹€. ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ 멀버 ν•¨μˆ˜κ°€ λ”°λ‘œ μžˆλ‹€λ©΄ 거의 항상 그게 더 λΉ λ¦…λ‹ˆλ‹€.

Q4. β€œbinary_search의 비ꡐ가 < 두 번인 μ΄μœ λŠ”?”

strict weak ordering 만 μš”κ΅¬ν•˜λŠ” STL의 μΌκ΄€λœ 섀계 λ•Œλ¬Έμž…λ‹ˆλ‹€. == μ—°μ‚°μžκ°€ μ •μ˜λ˜μ§€ μ•Šμ€ νƒ€μž…(예: μ‚¬μš©μž μ •μ˜ 클래슀)도 <만 μ •μ˜λΌ 있으면 binary_searchλ₯Ό μ“Έ 수 μžˆμŠ΅λ‹ˆλ‹€. !(a < b) && !(b < a)κ°€ 참이면 두 값은 β€œλ™λ“±β€ν•˜λ‹€κ³  κ°„μ£Όν•©λ‹ˆλ‹€. 이건 std::setμ΄λ‚˜ std::map이 < λΉ„κ΅μžλ§ŒμœΌλ‘œ λ™μž‘ν•˜λŠ” 것과 같은 μ›λ¦¬μž…λ‹ˆλ‹€.

Q5. β€œlist에 binary_search μ“°λ©΄ λ™μž‘ν•˜λ‚˜μš”?”

λ™μž‘μ€ ν•©λ‹ˆλ‹€. binary_searchλŠ” ForwardIterator만 μš”κ΅¬ν•˜λ‹ˆκΉŒμš”. ν•˜μ§€λ§Œ std::listλŠ” RandomAccessIteratorκ°€ μ•„λ‹ˆλΌ 쀑간 μœ„μΉ˜λ‘œ μ ν”„ν•˜λŠ” 데 O(n) 거리 계산이 λ“€μ–΄κ°‘λ‹ˆλ‹€. κ²°κ΅­ 비ꡐ 횟수만 O(log n)이지 μ „μ²΄λŠ” O(n)이 λΌμ„œ μ˜λ―Έκ°€ μ—†μŠ΅λ‹ˆλ‹€. 이뢄 νƒμƒ‰μ˜ 이득을 보렀면 vector, deque, array 처럼 random accessκ°€ κ°€λŠ₯ν•œ μ»¨ν…Œμ΄λ„ˆλ₯Ό 써야 ν•©λ‹ˆλ‹€.

Q6. β€œfind와 binary_search 외에 λ‹€λ₯Έ 탐색 μ•Œκ³ λ¦¬μ¦˜μ€?”

std::find_if (μˆ μ–΄ 기반 μ„ ν˜•), std::find_first_of (μ—¬λŸ¬ 후보 쀑 첫 일치), std::adjacent_find (인접 동일 μ›μ†Œ), std::search (λΆ€λΆ„ μ‹œν€€μŠ€ λ§€μΉ­), std::count/std::count_if (개수 μ„ΈκΈ°), std::any_of/std::all_of/std::none_of (쑰건 μΆ©μ‘± μ—¬λΆ€) 등이 μžˆμŠ΅λ‹ˆλ‹€. μ •λ ¬ 자료 μ „μš©μœΌλ‘œλŠ” μ•žμ„œ λ§ν•œ lower_boundΒ·upper_boundΒ·equal_rangeκ°€ 핡심 familyμž…λ‹ˆλ‹€.

Q7. β€œbinary_search κ²°κ³Όλ₯Ό λ°›μ•„μ„œ μœ„μΉ˜λ₯Ό 또 lower_bound둜 찾으면 λΉ„νš¨μœ¨ μ•„λ‹Œκ°€μš”?”

μ •ν™•ν•©λ‹ˆλ‹€. κ·Έλž˜μ„œ μœ„μΉ˜κ°€ ν•„μš”ν•˜λ©΄ μ²˜μŒλΆ€ν„° lower_bound만 λΆ€λ₯΄λŠ” 게 μ •μ„μž…λ‹ˆλ‹€. νŒ¨ν„΄μ€ μ΄λ ‡κ²Œ λ©λ‹ˆλ‹€:

1
2
3
4
auto it = std::lower_bound(v.begin(), v.end(), value);
if (it != v.end() && *it == value) {
    // 찾음 + μœ„μΉ˜λŠ” it
}

binary_searchλŠ” 정말 β€œμžˆλƒ μ—†λƒβ€λ§Œ ν•„μš”ν•  λ•Œ, λ˜λŠ” μ˜λ„λ₯Ό λͺ…ν™•νžˆ ν‘œν˜„ν•˜κ³  싢을 λ•Œλ§Œ μ”λ‹ˆλ‹€.


8. μ–Έλ¦¬μ–Όμ—μ„œμ˜ 탐색 β€” Algo::Find / Algo::BinarySearch

핡심 ν•œ λ¬Έμž₯

언리얼은 Algo:: λ„€μž„μŠ€νŽ˜μ΄μŠ€μ— std:: μ•Œκ³ λ¦¬μ¦˜ λŒ€μ‘ ν•¨μˆ˜λ₯Ό 두고, μ»¨ν…Œμ΄λ„ˆ μžμ²΄μ—λ„ Find 같은 멀버 ν•¨μˆ˜λ₯Ό μ œκ³΅ν•΄ 인덱슀 λ˜λŠ” 포인터 기반으둜 λ™μž‘ν•©λ‹ˆλ‹€.

λŒ€μ‘ ν‘œ

std::Unreal Algo:: / 멀버 ν•¨μˆ˜λ°˜ν™˜
std::findAlgo::Find(Arr, Value)T* (λͺ» 찾으면 nullptr)
std::find_ifAlgo::FindByPredicateT*
std::binary_searchAlgo::BinarySearch(Arr, Value)int32 인덱슀 (λͺ» 찾으면 INDEX_NONE = -1)
std::lower_boundAlgo::LowerBoundint32
std::upper_boundAlgo::UpperBoundint32
std::sortAlgo::Sortvoid
TArray::Find(멀버 ν•¨μˆ˜)int32 인덱슀
TArray::Contains(멀버 ν•¨μˆ˜)bool

μ½”λ“œ μ˜ˆμ‹œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "Algo/Find.h"
#include "Algo/BinarySearch.h"

TArray<int32> Arr = {3, 1, 4, 1, 5, 9, 2, 6};

// μ„ ν˜• 탐색 β€” 인덱슀
int32 Idx = Arr.Find(5);                      // TArray 멀버 ν•¨μˆ˜
if (Idx != INDEX_NONE) { /* ... */ }

// μ„ ν˜• 탐색 β€” 포인터
int32* Ptr = Algo::Find(Arr, 5);
if (Ptr) { /* *Ptr μ‚¬μš© κ°€λŠ₯ */ }

// 이뢄 탐색 (μ •λ ¬ ν•„μˆ˜)
Arr.Sort();  // 1, 1, 2, 3, 4, 5, 6, 9
int32 BIdx = Algo::BinarySearch(Arr, 5);
if (BIdx != INDEX_NONE) { /* ... */ }

차이점

  • 언리얼은 int32 인덱슀 λ°˜ν™˜μ„ μ„ ν˜Έ β€” INDEX_NONE (-1) 맀크둜둜 not-found ν‘œν˜„
  • Algo::FindλŠ” 포인터 λ°˜ν™˜ β€” nullptr κ²€μ‚¬λ‘œ not-found 처리
  • TArray::Find / TArray::Contains β€” 멀버 ν•¨μˆ˜κ°€ κ°€μž₯ 일반적. μ•Œκ³ λ¦¬μ¦˜ ν•¨μˆ˜λ³΄λ‹€ μ½”λ“œκ°€ κ°„κ²°
  • 언리얼은 <algorithm> 직접 μ‚¬μš©λ„ κ°€λŠ₯ν•˜μ§€λ§Œ Algo:: family와 멀버 ν•¨μˆ˜κ°€ μ»¨λ²€μ…˜

9. 보강 β€” iterator Β· λ™μΉ˜νŒλ‹¨ Β· lower_bound vs find

본문을 읽고 μΆ”κ°€λ‘œ 생긴 의문(2026-05-06)을 ν•œ μ„Ήμ…˜μœΌλ‘œ 묢음. β‘  iteratorκ°€ λ­”κ°€ β‘‘ findλŠ” 인덱슀λ₯Ό λŒλ €μ£ΌλŠ”κ°€ μ΄ν„°λ ˆμ΄ν„°λ₯Ό λŒλ €μ£ΌλŠ”κ°€ β‘’ λ™μΉ˜νŒλ‹¨μ΄λž€ β‘£ lower_bound와 find의 결정적 차이.

9-1. iteratorλž€

μ»¨ν…Œμ΄λ„ˆ μ›μ†Œλ₯Ό κ°€λ¦¬ν‚€λŠ” β€œν¬μΈν„° 같은 객체”. ν¬μΈν„°μ²˜λŸΌ 역참쑰·증가·비ꡐ가 κ°€λŠ₯ν•˜μ§€λ§Œ, vectorΒ·listΒ·map λ“± λ‚΄λΆ€ ꡬ쑰가 λ‹€λ₯Έ μ»¨ν…Œμ΄λ„ˆλ₯Ό 같은 μΈν„°νŽ˜μ΄μŠ€λ‘œ 닀루기 μœ„ν•œ μΆ”μƒν™”μž…λ‹ˆλ‹€.

핡심 μ—°μ‚° μ„Έ κ°€μ§€:

μ—°μ‚°μ˜λ―Έ
*itμ—­μ°Έμ‘° β€” κ°€λ¦¬ν‚€λŠ” μ›μ†Œμ˜ κ°’
++itλ‹€μŒ μ›μ†Œλ‘œ 이동
it == end끝인지 비ꡐ (==/!=)
1
2
3
4
5
6
std::vector<int> v = {3, 1, 4};
auto it = v.begin();   // 첫 μ›μ†Œλ₯Ό 가리킴
*it;                   // 3
++it;                  // 두 번째둜 이동
*it;                   // 1
v.end();               // β˜… λ§ˆμ§€λ§‰μ˜ "λ‹€μŒ" 자리 β€” 유효 μ›μ†Œ X (past-the-end)

end()λŠ” 유효 μ›μ†Œκ°€ μ•„λ‹ˆλ‹€ β€” λ§ˆμ§€λ§‰ μ›μ†Œ λ‹€μŒμ˜ 가상 μœ„μΉ˜(past-the-end). κ·Έλž˜μ„œ STL의 λͺ¨λ“  μ•Œκ³ λ¦¬μ¦˜μ€ [first, last) λ°˜μ—΄λ¦° κ΅¬κ°„μœΌλ‘œ λ™μž‘ν•©λ‹ˆλ‹€. findκ°€ λͺ» 찾으면 lastλ₯Ό λ°˜ν™˜ν•œλ‹€λŠ” 말은 β€œμœ νš¨ν•˜μ§€ μ•Šμ€ 끝 μžλ¦¬β€λ₯Ό κ°€λ¦¬ν‚¨λ‹€λŠ” 뜻이라 μ•ˆμ „ν•©λ‹ˆλ‹€.

iterator μΉ΄ν…Œκ³ λ¦¬ (강함 순)

μΉ΄ν…Œκ³ λ¦¬κ°€λŠ₯ μ—°μ‚°λŒ€ν‘œ μ»¨ν…Œμ΄λ„ˆ
Input++it, *it(읽기 μ „μš©, 1회)istream_iterator
Forward+ *it둜 μ—¬λŸ¬ 번 읽기forward_list
Bidirectional+ --it μ—­λ°©ν–₯list, set, map
Random Access+ it + n, it[n], it < it2vector, deque, array

β†’ binary_searchκ°€ vectorμ—μ„œ μ§„μ§œ O(log n)인 이유 = Random Accessμ—¬μ„œ 쀑간 점프가 O(1). β†’ list에 binary_searchλ₯Ό 써도 λ™μž‘ν•˜μ§€λ§Œ 점프가 O(n)이라 의미 μ—†λŠ” μ΄μœ λ„ κ°™μŒ.

9-2. findλŠ” 인덱슀? iterator?

std::findλŠ” iteratorλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. 인덱슀 μ•„λ‹™λ‹ˆλ‹€. λͺ» 찾으면 인덱슀 -1이 μ•„λ‹ˆλΌ last (= v.end()) λ₯Ό λŒλ €μ€λ‹ˆλ‹€.

1
2
3
4
5
6
auto it = std::find(v.begin(), v.end(), 999);
if (it == v.end()) { /* λͺ» 찾음 */ }            // ← 정석 νŒ¨ν„΄
if (it != v.end()) { /* 찾음 β€” *it μ‚¬μš© κ°€λŠ₯ */ }

// μΈλ±μŠ€κ°€ ν•„μš”ν•˜λ©΄ λ³€ν™˜
int idx = std::distance(v.begin(), it);

μ–Έμ–΄Β·λΌμ΄λΈŒλŸ¬λ¦¬λ³„ not-found ν‘œν˜„ 차이 β€” ν—·κ°ˆλ¦¬λŠ” 지점

APIλ°˜ν™˜ νƒ€μž…λͺ» μ°Ύμ•˜μ„ λ•Œ
std::find (C++ STL)iteratorlast (= end())
std::string::findsize_tstd::string::npos (= -1을 unsigned둜)
TArray::Find (Unreal)int32 인덱슀INDEX_NONE (= -1)
Algo::Find (Unreal)T* 포인터nullptr
std::map::find (멀버)iteratorend()

β†’ β€œfindλŠ” λͺ» 찾으면 -1” 은 std::stringμ΄λ‚˜ 언리얼 μ»¨λ²€μ…˜μ΄μ§€, <algorithm>의 std::findκ°€ μ•„λ‹˜. β†’ λͺ¨λ“  STL μ•Œκ³ λ¦¬μ¦˜μ€ not-found = last 둜 톡일.

9-3. λ™μΉ˜νŒλ‹¨(equivalence) β€” ==이 μ•„λ‹ˆλΌ < 두 번

binary_searchλŠ” ==둜 같은지 보지 μ•Šκ³  <λ₯Ό 두 번 ν˜ΈμΆœν•΄ β€œμ–΄λŠ μͺ½λ„ 더 μž‘μ§€ μ•Šλ‹€β€ 둜 같은지 νŒλ‹¨ν•©λ‹ˆλ‹€. 이걸 λ™μΉ˜(equivalence) 라고 λΆ€λ₯΄λ©°, 일반 동등성(equality)κ³Ό κ΅¬λΆ„λ©λ‹ˆλ‹€.

1
2
3
4
5
// equality (find의 방식)
a == b

// equivalence (binary_search Β· set Β· map의 방식)
!(a < b) && !(b < a)

μ™œ ꡳ이 μ΄λ ‡κ²Œ?

  • <만 μ •μ˜λΌ μžˆμ–΄λ„ λ™μž‘ν•˜λ„λ‘ λ§Œλ“  STL의 μΌκ΄€λœ 섀계
  • μ‚¬μš©μž μ •μ˜ ν΄λž˜μŠ€μ—μ„œ ==을 μ•ˆ λ§Œλ“€κ³  <만 λ§Œλ“€μ–΄λ„ binary_searchΒ·setΒ·map이 λͺ¨λ‘ μž‘λ™
  • 이걸 strict weak ordering이라고 뢀름 β€” < λΉ„κ΅μžκ°€ λ§Œμ‘±ν•΄μ•Ό ν•˜λŠ” μˆ˜ν•™μ  쑰건
1
2
3
4
5
6
7
8
9
10
struct Point {
    int x, y;
    bool operator<(const Point& o) const { return x < o.x; }
    // operator== 없어도 OK
};

std::vector<Point> pts = { {1,0}, {3,0}, {5,0} };
std::binary_search(pts.begin(), pts.end(), Point{3, 99});
// β†’ xμ’Œν‘œλ§Œ 비ꡐ β†’ !(3<3) && !(3<3) = true β†’ λ™μΉ˜λ‘œ νŒλ‹¨ β†’ true
// yκ°€ 달라도 "λ™μΉ˜"둜 λ΄„ β€” 이게 equivalence와 equality의 핡심 차이

β†’ ==λŠ” 객체 μžμ²΄κ°€ κ°™μŒ (entity equality) β†’ λ™μΉ˜λŠ” μˆœμ„œ κΈ°μ€€μ—μ„œ 같은 μœ„μΉ˜ (μ–΄λŠ μͺ½λ„ 더 μž‘μ§€ μ•ŠμŒ) β†’ λ‘˜μ΄ λ‹€λ₯Ό 수 μžˆλ‹€λŠ” 점이 함정 β€” setμ—μ„œ 같은 ν‚€λ‘œ μ·¨κΈ‰λ˜λŠ” 두 값이 ==λ‘œλŠ” λ‹€λ₯Ό 수 있음.

9-4. lower_bound vs find β€” 결정적 차이

λ‘˜ λ‹€ β€œμœ„μΉ˜ iteratorλ₯Ό λŒλ €μ€€λ‹€β€λŠ” 점은 κ°™μ§€λ§Œ, μ „μ œΒ·μ‹œκ°„λ³΅μž‘λ„Β·λ°˜ν™˜ μ˜λ―ΈΒ·λΆ€κ°€ λŠ₯λ ₯이 λ‹€λ¦…λ‹ˆλ‹€. κ°€μž₯ 큰 함정은 lower_boundλŠ” λͺ» 찾아도 lastκ°€ μ•„λ‹Œ μœ„μΉ˜λ₯Ό 가리킬 수 μžˆλ‹€λŠ” 점.

λΉ„κ΅ν‘œ

ν•­λͺ©std::findstd::lower_bound
μ•Œκ³ λ¦¬μ¦˜μ„ ν˜•μ΄λΆ„
μ •λ ¬ μ „μ œλΆˆν•„μš”ν•„μˆ˜
μ‹œκ°„λ³΅μž‘λ„O(n)O(log n)
비ꡐ μ—°μ‚°μž==<
λ°˜ν™˜μΌμΉ˜ν•˜λŠ” 첫 iteratorvalue 이상인 첫 iterator
λͺ» 찾을 λ•Œ λ°˜ν™˜last (λͺ…ν™•)last λ˜λŠ” value보닀 큰 λ‹€λ₯Έ μœ„μΉ˜ (μΆ”κ°€ 검사 ν•„μš”)
λΆ€κ°€ μš©λ„μœ„μΉ˜ μ°ΎκΈ°λ§Œμ •λ ¬ μœ μ§€ μ‚½μž… μœ„μΉ˜ 계산
iterator μš”κ΅¬InputIteratorForwardIterator (μ‹€νš¨ RandomAccess)

함정 β€” lower_boundλŠ” 두 단계 검사가 ν•„μˆ˜

1
2
3
4
5
6
7
8
9
10
std::vector<int> v = {1, 3, 5, 7};   // 정렬됨, 4λŠ” μ—†μŒ

// (A) find β€” ν•œ 번만 κ²€μ‚¬ν•˜λ©΄ 됨
auto it1 = std::find(v.begin(), v.end(), 4);
if (it1 != v.end()) { /* 찾음 */ }   // it1 == end() λΌμ„œ μ§„μž… μ•ˆ 함 ← λͺ…ν™•

// (B) lower_bound β€” itλŠ” 5λ₯Ό 가리킴 (4 이상 첫 μœ„μΉ˜)
auto it2 = std::lower_bound(v.begin(), v.end(), 4);
// it2 != v.end() 만 κ²€μ‚¬ν•˜λ©΄ μ•ˆ 됨!
if (it2 != v.end() && *it2 == 4) { /* 찾음 */ }   // ← 두 단계 검사 ν•„μˆ˜

β†’ find의 lastλŠ” β€œμ—†λ‹€β€ β†’ lower_bound의 lastλŠ” β€œvalue보닀 ν¬κ±°λ‚˜ 같은 게 ν•˜λ‚˜λ„ 없닀” (즉 λͺ¨λ“  μ›μ†Œκ°€ value 미만) β†’ lower_boundκ°€ lastκ°€ μ•„λ‹Œ μœ„μΉ˜λ₯Ό κ°€λ¦¬μΌœλ„ 그게 value인지 μ•„λ‹Œμ§€λŠ” 별도 검사 ν•„μš”.

lower_bound만의 λŠ₯λ ₯ β€” μ •λ ¬ μœ μ§€ μ‚½μž…

1
2
3
4
std::vector<int> v = {1, 3, 5, 7};
auto pos = std::lower_bound(v.begin(), v.end(), 4);
v.insert(pos, 4);
// v = {1, 3, 4, 5, 7} β€” μ •λ ¬ μœ μ§€

β†’ findλ‘œλŠ” λΆˆκ°€λŠ₯. lower_boundλŠ” β€œνƒμƒ‰ + μ‚½μž… μœ„μΉ˜ 결정” 두 역할을 κ²Έν•©λ‹ˆλ‹€. β†’ κ·Έλž˜μ„œ μ •λ ¬λœ μžλ£Œμ—μ„œ β€œμ΄ 값이 μžˆλŠ”μ§€ + μ—†μœΌλ©΄ μ–΄λ”” λΌμšΈμ§€β€λ₯Ό ν•œ λ²ˆμ— μ²˜λ¦¬ν•  λ•Œ lower_bound만 λΆ€λ₯΄λ©΄ 됨.

9-5. equal_range β€” μ‚¬μš©λ²•κ³Ό λ°˜ν™˜κ°’ λΆ„ν•΄

std::equal_rangeλŠ” μ •λ ¬ κ΅¬κ°„μ—μ„œ value와 λ™μΉ˜μΈ μ›μ†Œλ“€μ˜ λ²”μœ„λ₯Ό pair<iterator, iterator> 둜 λ°˜ν™˜ν•©λ‹ˆλ‹€. 즉 {lower_bound, upper_bound} ν•œ μŒμ„ ν•œ λ²ˆμ— λŒλ €μ€λ‹ˆλ‹€. 쀑볡이 μžˆλŠ” μ •λ ¬ μžλ£Œμ—μ„œ β€œκ°™μ€ 값이 μ–΄λ””λΆ€ν„° μ–΄λ””κΉŒμ§€λƒβ€λ₯Ό ꡬ할 λ•Œ 핡심.

μ‹œκ·Έλ‹ˆμ²˜

1
2
3
4
5
6
7
8
template <class ForwardIt, class T>
std::pair<ForwardIt, ForwardIt>
equal_range(ForwardIt first, ForwardIt last, const T& value);

// λΉ„κ΅μž 버전
template <class ForwardIt, class T, class Compare>
std::pair<ForwardIt, ForwardIt>
equal_range(ForwardIt first, ForwardIt last, const T& value, Compare comp);
  • 헀더: <algorithm>
  • λ°˜ν™˜: pair<It, It> β€” .first = lower_bound, .second = upper_bound
  • μ‹œκ°„λ³΅μž‘λ„: O(log n) 비ꡐ (RandomAccess κΈ°μ€€)
  • μ „μ œ: 정렬돼 μžˆμ–΄μ•Ό 함 (μ•ˆ 되면 UB)

λ°˜ν™˜κ°’μ˜ 의미 μ‹œκ°ν™”

1
2
3
4
5
6
7
8
9
v = {1, 2, 2, 2, 3, 4}      (인덱슀 0 1 2 3 4 5)
                ^
       equal_range(v.begin(), v.end(), 2)

         β”Œβ”€β”€β”€β”€ .first  (lower_bound) β†’ 인덱슀 1, *it == 2 (첫 2)
         β”‚   β”Œβ”€β”€ .second (upper_bound) β†’ 인덱슀 4, *it == 3 (2 λ‹€μŒ 첫 μœ„μΉ˜)
         β–Ό   β–Ό
[1] [2] [2] [2] [3] [4]
     └─── λ™μΉ˜ λ²”μœ„ [first, second) = 인덱슀 1~3 β”€β”€β”€β”˜

β†’ .first = value 이상 첫 μœ„μΉ˜ (= 첫 λ“±μž₯ μœ„μΉ˜) β†’ .second = value 초과 첫 μœ„μΉ˜ (= λ§ˆμ§€λ§‰ λ“±μž₯ + 1, λ°˜μ—΄λ¦° 끝) β†’ [.first, .second) λ°˜μ—΄λ¦° ꡬ간이 value와 λ™μΉ˜μΈ μ›μ†Œ 전체

μ‚¬μš© νŒ¨ν„΄ β€” 4κ°€μ§€

β‘  개수 μ„ΈκΈ°
1
2
3
std::vector<int> v = {1, 2, 2, 2, 3, 4};
auto [lo, hi] = std::equal_range(v.begin(), v.end(), 2);   // C++17 ꡬ쑰적 바인딩
std::cout << std::distance(lo, hi) << "\n";                // 3
β‘‘ 쑴재 μ—¬λΆ€ 확인
1
2
3
auto [lo, hi] = std::equal_range(v.begin(), v.end(), 2);
if (lo != hi) { /* 있음 */ }     // 거리 > 0
else          { /* μ—†μŒ */ }     // 거리 == 0 β†’ 두 iteratorκ°€ 같은 μœ„μΉ˜

β†’ λͺ» μ°Ύμ•˜μ„ λ•Œλ„ .first == .second κ°€ 되며 같은 μœ„μΉ˜λ₯Ό 가리킴 β€” κ·Έ μžλ¦¬κ°€ μ‚½μž… μœ„μΉ˜.

β‘’ λ™μΉ˜ μ›μ†Œ 전체 순회
1
2
3
4
auto [lo, hi] = std::equal_range(v.begin(), v.end(), 2);
for (auto it = lo; it != hi; ++it) {
    std::cout << *it << " ";   // 2 2 2
}
β‘£ ꡬ쑰적 바인딩 없이 (C++14 μ΄ν•˜)
1
2
3
4
auto p = std::equal_range(v.begin(), v.end(), 2);
auto lo = p.first;
auto hi = p.second;
int  cnt = static_cast<int>(std::distance(lo, hi));

multiset / multimapμ—μ„œμ˜ ν™œμš©

equal_rangeκ°€ μ§„μ§œ 빛을 λ³΄λŠ” 곳은 쀑볡 ν‚€λ₯Ό ν—ˆμš©ν•˜λŠ” μ—°κ΄€ μ»¨ν…Œμ΄λ„ˆμž…λ‹ˆλ‹€. 같은 ν‚€μ˜ λͺ¨λ“  값을 ν•œ λ²ˆμ— μž‘μ•„λ‚Ό λ•Œ.

1
2
3
4
5
6
7
8
9
std::multimap<std::string, int> scores = {
    {"Alice", 90}, {"Alice", 85}, {"Bob", 70}, {"Alice", 95}
};

auto [lo, hi] = scores.equal_range("Alice");   // 멀버 ν•¨μˆ˜ β€” O(log n)
for (auto it = lo; it != hi; ++it) {
    std::cout << it->first << ": " << it->second << "\n";
    // Alice: 90 / Alice: 85 / Alice: 95
}

β†’ multimap/multisetμ—μ„œ 같은 ν‚€ λͺ¨λ‘ κ°€μ Έμ˜€λŠ” μœ μΌν•œ 정석 방법 (반볡 findλ‘œλŠ” 첫 개만). β†’ 멀버 ν•¨μˆ˜ equal_rangeκ°€ λ”°λ‘œ μžˆλ‹€ β€” μ•Œκ³ λ¦¬μ¦˜ std::equal_range보닀 자료ꡬ쑰 μΉœν™”μ .

λͺ» μ°Ύμ•˜μ„ λ•Œ β€” .first == .second 의 의미

1
2
3
4
5
std::vector<int> v = {1, 3, 5, 7};
auto [lo, hi] = std::equal_range(v.begin(), v.end(), 4);
// lo == hi (λ‘˜ λ‹€ 5 μœ„μΉ˜, 인덱슀 2λ₯Ό 가리킴)
// distance(lo, hi) == 0 β†’ 4λŠ” μ—†μŒ
// κ·Έ μžλ¦¬κ°€ μ •λ ¬ μœ μ§€ μ‚½μž… μœ„μΉ˜

β†’ β€œμ°Ύμ§€ λͺ»ν•œ μœ„μΉ˜ = μ •λ ¬ μœ μ§€ μ‚½μž… μœ„μΉ˜β€λΌλŠ” lower_bound의 μ„±μ§ˆμ΄ κ·ΈλŒ€λ‘œ μœ μ§€λ¨.

lower_bound + upper_bound λ”°λ‘œ 호좜 vs equal_range

1
2
3
4
5
6
// (A) λ”°λ‘œ 호좜 β€” 트리/이뢄 탐색 2번
auto lo = std::lower_bound(v.begin(), v.end(), 2);
auto hi = std::upper_bound(v.begin(), v.end(), 2);

// (B) equal_range β€” ν•œ λ²ˆμ—
auto [lo, hi] = std::equal_range(v.begin(), v.end(), 2);

β†’ ν‘œμ€€μ€ (B)λ₯Ό 단일 패슀둜 μ΅œμ ν™” κ°€λŠ₯ν•˜κ²Œ λͺ…μ„Έ β€” 일뢀 κ΅¬ν˜„μ€ λΆ„κΈ° μ ˆμ•½. μ˜λ„ ν‘œν˜„λ„ λͺ…ν™•. β†’ β€œλ²”μœ„κ°€ ν•„μš”ν•˜λ‹€β€κ°€ μ˜λ„λ©΄ equal_range 직선택.

λ°˜ν™˜κ°’ 정리 μΉ΄λ“œ

1
2
3
4
5
6
7
equal_range(λ²”μœ„, value) β†’ pair<It, It>
  β”œβ”€ .first  = lower_bound  β†’ value 이상 첫 μœ„μΉ˜
  β”œβ”€ .second = upper_bound  β†’ value 초과 첫 μœ„μΉ˜
  β”œβ”€ [first, second)        β†’ value와 λ™μΉ˜μΈ μ›μ†Œ 전체
  β”œβ”€ distance(first, second) β†’ value의 개수
  β”œβ”€ first == second        β†’ μ—†μŒ + κ·Έ μžλ¦¬κ°€ μ‚½μž… μœ„μΉ˜
  └─ multiμ»¨ν…Œμ΄λ„ˆμ—μ„œ 핡심 β€” 같은 ν‚€ 전체 κ°€μ Έμ˜€κΈ°

언리얼 λŒ€μ‘

언리얼은 Algo:: λ„€μž„μŠ€νŽ˜μ΄μŠ€μ— EqualRangeκ°€ μ—†κ±°λ‚˜ 맀우 μ œν•œμ μ΄λΌ 보톡 직접 μ‘°ν•©:

1
2
3
4
5
6
7
8
TArray<int32> Arr = {1, 2, 2, 2, 3, 4};
int32 Lo = Algo::LowerBound(Arr, 2);   // 1
int32 Hi = Algo::UpperBound(Arr, 2);   // 4
int32 Count = Hi - Lo;                 // 3

// TMultiMap의 λ™μΉ˜ ν‚€ λͺ¨λ‘ κ°€μ Έμ˜€κΈ°
TArray<FValue> Values;
MultiMap.MultiFind(Key, Values);       // 멀버 ν•¨μˆ˜ β€” equal_range λŒ€μ‘

β†’ μ–Έλ¦¬μ–Όμ—μ„œλŠ” MultiFind / LowerBound+UpperBound 쑰합이 μ»¨λ²€μ…˜.


10. 보강 β€” 큰 λ°μ΄ν„°μ—μ„œ find vs binary_search 선택

β€œν° 데이터면 무쑰건 binary_searchκ°€ λ‚«μ§€ μ•Šλ‚˜?β€λŠ” 절반만 λ§žλŠ” λ‹΅μž…λ‹ˆλ‹€. μ •λ ¬ λΉ„μš©Β·μ‘°νšŒ νšŸμˆ˜Β·μΊμ‹œ μΉœν™”μ„±μ΄ 손읡을 κ°€λ¦…λ‹ˆλ‹€. 데이터가 클수둝 였히렀 λ‹€μ„― κ°€μ§€ λ³€μˆ˜λ₯Ό λ”°μ Έμ•Ό ν•©λ‹ˆλ‹€.

10-1. κ²°λ‘ λΆ€ν„° β€” 5κ°€μ§€ μ‹œλ‚˜λ¦¬μ˜€

μƒν™©μ •λ‹΅μ΄μœ 
이미 정렬돼 있음 + λ‹¨λ°œ 쑰회binary_search / lower_boundμ •λ ¬ λΉ„μš© 0, O(log n) κ·ΈλŒ€λ‘œ 이득
μ •λ ¬ μ•ˆ 됨 + 1회 쑰회findμ •λ ¬ λΉ„μš© O(n log n) > 탐색 λΉ„μš© O(n). 정렬은 손해
μ •λ ¬ μ•ˆ 됨 + k회 반볡 쑰회kκ°€ 크면 μ •λ ¬+binary_search손읡뢄기점은 k ≳ log n λΆ€κ·Ό
n이 맀우 큼 + λ™μ‹œμ„±Β·μ‚½μž… 잦음unordered_set/map (ν•΄μ‹œ)평균 O(1). λΉˆλ„ 높은 쑰회면 자료ꡬ쑰 자체λ₯Ό λ°”κΏˆ
n이 μž‘μŒ (~μˆ˜μ‹­~수백)findμΊμ‹œΒ·λΆ„κΈ° 예츑 효과둜 μ„ ν˜•μ΄ 더 λΉ λ₯Ό λ•Œλ„ 있음

10-2. 손읡뢄기점 β€” μ •λ ¬ν•΄μ•Ό 이득인가

쑰회λ₯Ό k번 ν•œλ‹€κ³  κ°€μ •ν•˜κ³  두 μ „λž΅ λΉ„μš©μ„ λΉ„κ΅ν•©λ‹ˆλ‹€.

1
2
(A) 맀번 find             : k * O(n)        = O(k·n)
(B) μ •λ ¬ 1회 + binary_search k번 : O(n log n) + k * O(log n)

(B) < (A) κ°€ 되렀면 λŒ€λž΅ k > log n 일 λ•ŒλΆ€ν„°. n=10⁢이면 logβ‚‚n β‰ˆ 20 β†’ 20번 λ„˜κ²Œ μ‘°νšŒν•œλ‹€λ©΄ 정렬이 이득. λ°˜λŒ€λ‘œ ν•œλ‘ 번만 μ°Ύκ³  λλ‚˜λ©΄ κ·Έλƒ₯ findκ°€ λΉ λ¦…λ‹ˆλ‹€.

1
2
3
4
5
6
7
// μ•ˆ 쒋은 νŒ¨ν„΄ β€” ν•œ 번 찾을 건데 μ •λ ¬λΆ€ν„° 함
std::sort(v.begin(), v.end());                           // O(n log n)
bool ok = std::binary_search(v.begin(), v.end(), x);     // O(log n)
// 합계 O(n log n) > std::find의 O(n)

// 쒋은 νŒ¨ν„΄ β€” μΌνšŒμ„±μ΄λ©΄ κ·Έλƒ₯ find
auto it = std::find(v.begin(), v.end(), x);              // O(n)

10-3. μΊμ‹œ μΉœν™”μ„± β€” μž‘μ€ 데이터에선 μ„ ν˜•μ΄ λΉ λ₯Ό 수 μžˆλ‹€

μ•Œκ³ λ¦¬μ¦˜ λ³΅μž‘λ„μ™€ λ³„κ°œλ‘œ λ©”λͺ¨λ¦¬ μ ‘κ·Ό νŒ¨ν„΄μ΄ μ‹€μ œ 속도λ₯Ό κ°€λ₯Έλ‹€. 큰 λ°μ΄ν„°μ—μ„œ λ‹¨μˆœ 비ꡐ 횟수만 보면 binary_searchκ°€ μ••μŠΉμ΄μ§€λ§Œ, 데이터가 μž‘μ•„ L1/L2 μΊμ‹œμ— λ‹€ μ˜¬λΌκ°€λŠ” κ²½μš°μ—” μ„ ν˜•μ΄ 더 λΉ λ₯Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

μΈ‘λ©΄μ„ ν˜• 탐색 (find)이뢄 탐색 (binary_search)
λ©”λͺ¨λ¦¬ μ ‘κ·Όμˆœμ°¨ β€” prefetcher ν™œμš©λ¬΄μž‘μœ„ 점프 β€” μΊμ‹œ 미슀 倚
λΆ„κΈ° μ˜ˆμΈ‘λ‹¨μˆœ (!= last만)λΆ„κΈ° 倚 (mid λΉ„κ΅λ§ˆλ‹€)
n이 μž‘μ„ λ•ŒλΉ λ¦„ (수백~수천 λ‹¨μœ„)μ˜€λ²„ν—€λ“œκ°€ 이득보닀 큼
n이 클 λ•ŒO(n) β€” μ••λ„μ μœΌλ‘œ λŠλ¦Όμ••λ„μ μœΌλ‘œ 빠름

손읡뢄기 체감 (λŒ€λž΅):

  • n < μ•½ 64~128 β†’ μ„ ν˜•μ΄ 더 λΉ λ₯΄κ±°λ‚˜ λΉ„μŠ· (CPUΒ·νƒ€μž…μ— 따라 닀름)
  • n > μ•½ 1,000 β†’ 이뢄 탐색이 λͺ…ν™•νžˆ 이득
  • n > 100,000 β†’ 이뢄 μ••μŠΉ, μ„ ν˜•μ€ 사싀상 λͺ» 씀

β†’ κ·Έλž˜μ„œ ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬λ“€μ΄ μž‘μ€ ꡬ간에선 μ„ ν˜•μœΌλ‘œ ν΄λ°±ν•˜λŠ” ν•˜μ΄λΈŒλ¦¬λ“œ μ •λ ¬(introsort + insertion sort)을 μ“°λŠ” 것과 같은 원리.

10-4. n이 정말 클 λ•Œ β€” 자료ꡬ쑰λ₯Ό μ˜μ‹¬ν•˜λΌ

vectorμ—μ„œ binary_search μΉ΄λ“œλ§Œ λ§Œμ§€μž‘κ±°λ¦¬μ§€ 말고, μ‘°νšŒκ°€ 핡심 μ›Œν¬λ‘œλ“œλΌλ©΄ 자료ꡬ쑰 자체λ₯Ό λ°”κΎΈλŠ” 게 보톡 더 큰 차이λ₯Ό λ§Œλ“­λ‹ˆλ‹€.

μžλ£Œκ΅¬μ‘°ν‰κ·  μ‘°νšŒλΉ„κ³ 
μ •λ ¬λœ vector + binary_searchO(log n)μΊμ‹œ μΉœν™”μ , λ©”λͺ¨λ¦¬ 컴팩트, μ‚½μž…μ€ O(n)
std::set / std::map (RB-Tree)O(log n)μ‚½μž…Β·μ‚­μ œ O(log n), λ©”λͺ¨λ¦¬ λ‹¨νŽΈν™”
std::unordered_set / unordered_map평균 O(1)ν•΄μ‹œ. 데이터 맀우 클 λ•Œ 1μˆœμœ„
μ™ΈλΆ€ 색인 (B-Tree, Trie)μΌ€μ΄μŠ€λ³„DB·파일 μ‹œμŠ€ν…œΒ·λ¬Έμžμ—΄

β†’ β€œμ •λ ¬λœ vector + binary_searchβ€œλŠ” λ©”λͺ¨λ¦¬ 효율과 μΊμ‹œ μΉœν™”μ„±μœΌλ‘œ μ’…μ’… set보닀 λΉ λ¦…λ‹ˆλ‹€. 정적 데이터(ν•œ 번 λΉŒλ“œ ν›„ 쑰회만)에 특히 유리. β†’ 동적 μ‚½μž…μ΄ 잦으면 unordered_set λ˜λŠ” set 선택.

10-5. μ‹€μ „ κ°€μ΄λ“œ β€” μ˜μ‚¬κ²°μ • 흐름

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
                        탐색이 ν•„μš”ν•˜λ‹€
                              β”‚
                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            데이터 정렬됨?              μ•„λ‹ˆμ˜€
                β”‚                          β”‚
              예                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                β”‚            μ‘°νšŒκ°€ 1~λͺ‡ 번         μ‘°νšŒκ°€ 많음(k > log n)
                β”‚                  β”‚                       β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”         find             자료ꡬ쑰λ₯Ό λ°”κΏ€ 수 μžˆλ‚˜?
     μœ„μΉ˜ ν•„μš”?     쑴재만?       (O(n))                    β”‚
        β”‚               β”‚                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
   lower_bound    binary_search                예                  μ•„λ‹ˆμ˜€
   (O(log n))      (O(log n))                  β”‚                     β”‚
                                       unordered_set        sort + binary_search
                                       /map (O(1))          (O(n log n + k log n))

10-6. 자주 ν•˜λŠ” μ‹€μˆ˜

  • β€œν° λ°μ΄ν„°λ‹ˆκΉŒ 무쑰건 binary_search” β€” μ •λ ¬ λΉ„μš©μ„ 빼먹음. μ •λ ¬ μ•ˆ 된 데이터λ₯Ό ν•œ 번만 찾을 κ±°λ©΄ findκ°€ μ •λ‹΅.
  • vector에 맀번 sort ν˜ΈμΆœν•˜κ³  binary_search β€” sort μžμ²΄κ°€ O(n log n). setμ΄λ‚˜ unordered_set을 μ²˜μŒλΆ€ν„° μ“°λŠ” 게 맞음.
  • list에 binary_search β€” Random Accessκ°€ μ•„λ‹ˆλΌ 점프가 O(n). μ΄λΆ„μ˜ 이득 0. listμ—” κ·Έλƒ₯ find.
  • μ—°κ΄€ μ»¨ν…Œμ΄λ„ˆμ— μ•Œκ³ λ¦¬μ¦˜ std::find β€” set/map::find 멀버 ν•¨μˆ˜κ°€ O(log n) 보μž₯. μ•Œκ³ λ¦¬μ¦˜ std::findλŠ” O(n)이라 손해 큼.

10-7. ν•œ 쀄 μš”μ•½

1
2
3
4
5
큰 데이터 + 정렬됨        β†’ binary_search (O(log n))   ← μ••μŠΉ
큰 데이터 + μ •λ ¬ μ•ˆ 됨 + 1회 β†’ find          (O(n))     ← μ •λ ¬ λΉ„μš© νšŒν”Ό
큰 데이터 + μ •λ ¬ μ•ˆ 됨 + λ‹€νšŒ β†’ sort + binary_search    ← k > log nμ—μ„œ 이득
κ±°λŒ€ 데이터 + 쑰회 빈번    β†’ unordered_set/map (O(1))  ← 자료ꡬ쑰 ꡐ체가 μ •λ‹΅
μž‘μ€ 데이터 (~수백)         β†’ find도 μΆ©λΆ„ (μΊμ‹œΒ·λΆ„κΈ° 예츑 이점)

β†’ 핡심은 β€œμ •λ ¬ λΉ„μš© + 쑰회 λΉ„μš©β€μ„ ν•©μ³μ„œ 비ꡐ할 것, 그리고 μ§„μ§œ 큰 데이터면 자료ꡬ쑰 자체λ₯Ό μ˜μ‹¬ν•  것.


정리 β€” μ–Έμ œ 무엇을 μ“°λ‚˜

1
2
3
4
5
6
μ •λ ¬ μ•ˆ λκ±°λ‚˜, μΌνšŒμ„±, equality 비ꡐ μΆ©λΆ„  β†’ std::find
정렬됐고, 쑴재 μ—¬λΆ€λ§Œ ν•„μš”                   β†’ std::binary_search
정렬됐고, μœ„μΉ˜κΉŒμ§€ ν•„μš”                      β†’ std::lower_bound (+ *it == value 검사)
정렬됐고, 같은 κ°’ λ²”μœ„(쀑볡 λ‹€νšŒ) ν•„μš”        β†’ std::equal_range
μ •λ ¬ μœ μ§€ μ‚½μž…                              β†’ std::lower_bound + insert
μ—°κ΄€ μ»¨ν…Œμ΄λ„ˆ (set/map/unordered_*)         β†’ 멀버 ν•¨μˆ˜ .find()  β˜… μ•Œκ³ λ¦¬μ¦˜ X

핡심 μš”μ•½ μΉ΄λ“œ (재게재)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
std::find          β†’ O(n), iterator, μ •λ ¬ X, ==     | λͺ» 찾으면 end()
std::binary_search β†’ O(log n), bool, μ •λ ¬ β˜…, <두 번 | μœ„μΉ˜ λͺ¨λ¦„
                    ↓ μœ„μΉ˜κΉŒμ§€ ν•„μš”ν•˜λ©΄
std::lower_bound   β†’ O(log n), iterator (binary_search λ‚΄λΆ€)
                    | λͺ» 찾아도 end()κ°€ 아닐 수 있음 β†’ *it == value μΆ”κ°€ 검사

iterator      = μ»¨ν…Œμ΄λ„ˆ μ›μ†Œλ₯Ό κ°€λ¦¬ν‚€λŠ” 좔상 포인터. *it / ++it / it==end 3μ’…
                end()λŠ” past-the-end (유효 μ›μ†Œ μ•„λ‹˜). [first, last) λ°˜μ—΄λ¦° ꡬ간.
λ™μΉ˜(equivalence) = !(a<b)&&!(b<a). ==κ³Ό 닀름. < 만 μ •μ˜λ˜λ©΄ OK (strict weak ordering)

set/map β†’ 멀버 ν•¨μˆ˜ find() (O(log n))
unordered_map β†’ 멀버 ν•¨μˆ˜ find() (O(1) 평균)
μ•Œκ³ λ¦¬μ¦˜ std::find은 μ—°κ΄€ μ»¨ν…Œμ΄λ„ˆμ— μ“°λ©΄ 손해 (O(n))

언리얼: Algo::Find (T*), Algo::BinarySearch (int32 / INDEX_NONE),
       TArray::Find (멀버, int32)
이 κΈ°μ‚¬λŠ” μ €μž‘κΆŒμžμ˜ CC BY 4.0 λΌμ΄μ„ΌμŠ€λ₯Ό λ”°λ¦…λ‹ˆλ‹€.