Ver5.0 ๐งฐ STL ์๊ณ ๋ฆฌ์ฆ 3๋์ฅ: sort, find, transform ์ ๋๋ก ์จ๋จน๊ธฐ

๐งฐ STL ์๊ณ ๋ฆฌ์ฆ 3๋์ฅ: sort, find, transform ์ ๋๋ก ์จ๋จน๊ธฐ
์ผ, ๋ ํน์ ์์ง๋ ๋ฐฐ์ด ์ ๋ ฌํ๋ ค๊ณ ๋ฒ๋ธ ์ ๋ ฌ for๋ฌธ ๋ ๊ฒน ์ง๊ณ ์์ด? ์๋๋ฉด ๋ฒกํฐ์์ ๊ฐ ํ๋ ์ฐพ์ผ๋ ค๊ณ for (int i = 0; ...) ๋๋ฆฌ๋ฉด์ flag = true ์ธ์ฐ๊ณ ์์ง ์๊ณ ? ๐
๊ด์ฐฎ์, ๋ค๋ค ๊ทธ๋ ๊ฒ ์์ํด. ๊ทผ๋ฐ C++์๋ ์ด๋ฏธ ๊ฒ์ฆ๋ ๊ณ ์ฑ๋ฅ ๋๊ตฌ ์์๊ฐ ๊ธฐ๋ณธ์ผ๋ก ๋ค์ด ์์ด. ๊ทธ๊ฒ ๋ฐ๋ก STL ์๊ณ ๋ฆฌ์ฆ์ด์ผ.
์ค๋์ ๊ทธ์ค์์๋ ์ค๋ฌด์ ์ฝ๋ฉ ํ ์คํธ์์ ๊ฐ์ฅ ์์ฃผ ์ฐ๋ 3๋์ฅ, std::sort, std::find, std::transform์ ์น๊ตฌํํ ์ค๋ช ํ๋ฏ ํ๋์ฉ ๋ฏ์ด๋ณผ ๊ฑฐ์ผ. ์๊ฐ ๋ณต์ก๋ ๊ฐ์ ํฉํธ๋ ์ ํํ ์ฑ๊ธฐ๊ณ , ํํ ๋ฐ๋ ์ง๋ขฐ๋ ๊ฐ์ด ํผํด๊ฐ ๋ณด์๊ณ .
๐ง ๋จผ์ STL ์๊ณ ๋ฆฌ์ฆ์ ์ฒ ํ๋ถํฐ
STL(Standard Template Library)์ ํฌ๊ฒ ์ปจํ ์ด๋(vector, list, map ๋ฑ), ๋ฐ๋ณต์(iterator), ์๊ณ ๋ฆฌ์ฆ(sort, find ๋ฑ) ์ธ ์ถ์ผ๋ก ์ด๋ค์ ธ ์์ด. ์ฌ๊ธฐ์ ํต์ฌ ํฌ์ธํธ๋ ์๊ณ ๋ฆฌ์ฆ์ด ์ปจํ ์ด๋๋ฅผ ์ง์ ๋ชจ๋ฅธ๋ค๋ ๊ฑฐ์ผ.
์๊ณ ๋ฆฌ์ฆ์ ์ค์ง ๋ฐ๋ณต์ ํ ์๋ง ๋ฐ์. ๋ณดํต first์ last์ธ๋ฐ, ๋ฒ์๋ ๋ฐ์ด๋ฆฐ ๊ตฌ๊ฐ [first, last)์ผ. ์ฆ first๋ ํฌํจ, last๋ ํฌํจํ์ง ์์. ๊ทธ๋์ v.end()๋ ๋ง์ง๋ง ์์ "๋ค์" ์์น๋ฅผ ๊ฐ๋ฆฌํค๋ ๊ฑฐ๊ณ .
์ด ์ค๊ณ ๋๋ถ์ ๊ฐ์ std::find๋ฅผ vector, list, deque, ์ฌ์ง์ด ์ผ๋ฐ C ๋ฐฐ์ด(ํฌ์ธํฐ๋ ๋ฐ๋ณต์์ฒ๋ผ ๋์ํ๋๊น)์๋ ์ธ ์ ์์ด. ์ปจํ
์ด๋ N๊ฐ ร ์๊ณ ๋ฆฌ์ฆ M๊ฐ๋ฅผ NรM๋ฒ ๊ตฌํํ ํ์ ์์ด N+M์ผ๋ก ๋๋๋ ๊ฑฐ์ง. ์ด๊ฒ ๋ฐ๋ก ์ ๋ค๋ฆญ ํ๋ก๊ทธ๋๋ฐ์ ๋งค๋ ฅ์ด์ผ. โจ
๐ 1. std::sort โ ์ ๋ ฌ์ ๊ทธ๋ฅ ์ด๊ฑฐ ์ฐ๋ฉด ๋ผ
๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {5, 2, 9, 1, 7};
std::sort(v.begin(), v.end()); // ์ค๋ฆ์ฐจ์: 1 2 5 7 9
for (int x : v) std::cout << x << ' ';
}
๊ธฐ๋ณธ ๋น๊ต๋ operator<์ผ. ๊ทธ๋์ ์๋ฌด๊ฒ๋ ์ ๋๊ธฐ๋ฉด ์ค๋ฆ์ฐจ์์ด ๋ผ. ๋ด๋ฆผ์ฐจ์์ ๋น๊ต ํจ์๋ฅผ ๋๊ฒจ์ฃผ๋ฉด ๋.
std::sort(v.begin(), v.end(), std::greater<int>()); // 9 7 5 2 1
// C++14๋ถํฐ๋ std::greater<>() ์ฒ๋ผ ํ์
์๋ต ๊ฐ๋ฅ
std::sort(v.rbegin(), v.rend()); // ์ญ๋ฐฉํฅ ๋ฐ๋ณต์๋ก ์ค๋ฆ์ฐจ์ = ๊ฒฐ๊ณผ์ ์ผ๋ก ๋ด๋ฆผ์ฐจ์
์ฑ๋ฅ ํฉํธ: ์ผ๋ง๋ ๋นจ๋ผ?
C++11 ํ์ค๋ถํฐ std::sort๋ ์ต์
์ ๊ฒฝ์ฐ์๋ O(N log N) ๋ฒ์ ๋น๊ต๋ฅผ ๋ณด์ฅํ๋๋ก ๊ท์ ๋ผ ์์ด. (C++03 ์์ ์ "ํ๊ท " O(N log N)๋ง ์๊ตฌํ์์ด.)
๊ทธ๋์ ์ฃผ์ ๊ตฌํ์ฒด(GCC์ libstdc++, LLVM์ libc++, MSVC STL)๋ ๋ณดํต ์ธํธ๋ก์ํธ(Introsort)๋ฅผ ์จ. ํต์ํธ๋ก ๋ฌ๋ฆฌ๋ค๊ฐ ์ฌ๊ท ๊น์ด๊ฐ ๋๋ฌด ๊น์ด์ง๋ฉด ํ์ํธ๋ก ๊ฐ์ํ๊ณ , ๊ตฌ๊ฐ์ด ์์์ง๋ฉด ์ฝ์
์ ๋ ฌ๋ก ๋ง๋ฌด๋ฆฌํ๋ ํ์ด๋ธ๋ฆฌ๋ ๋ฐฉ์์ด์ผ. ํต์ํธ์ ํ๊ท ์๋ + ํ์ํธ์ ์ต์
๋ณด์ฅ, ๋ ๋ค ์ฑ๊ธฐ๋ ์๋ฆฌํ ๋
์์ด์ง. ๐
std::sort๋ ๋๋ค ์ก์ธ์ค ๋ฐ๋ณต์๊ฐ ํ์ํด. ๊ทธ๋์ std::list์๋ ๋ชป ์จ! list๋ ์์ฒด ๋ฉค๋ฒ ํจ์ lst.sort()๋ฅผ ์จ์ผ ํด. std::sort(lst.begin(), lst.end()) ํ๋ฉด ์ปดํ์ผ ์๋ฌ๊ฐ ๊ธธ๊ฒ ์์์ง ๊ฑฐ์ผ.๋๋ค๋ก ์ปค์คํ ์ ๋ ฌํ๊ธฐ
์ค์ ์์ ๊ตฌ์กฐ์ฒด๋ฅผ ์ ๋ ฌํ๋ ์ผ์ด ํจ์ฌ ๋ง์. ์๋ฅผ ๋ค์ด ํ์์ ์ ์ ๋ด๋ฆผ์ฐจ์, ์ ์๊ฐ ๊ฐ์ผ๋ฉด ์ด๋ฆ ์ค๋ฆ์ฐจ์์ผ๋ก ์ ๋ ฌํด๋ณด์.
struct Student {
std::string name;
int score;
};
std::vector<Student> s = {{"๋ฏผ์", 90}, {"์ง์", 95}, {"์ฒ ์", 90}};
std::sort(s.begin(), s.end(), [](const Student& a, const Student& b) {
if (a.score != b.score) return a.score > b.score; // ์ ์ ๋ด๋ฆผ์ฐจ์
return a.name < b.name; // ์ด๋ฆ ์ค๋ฆ์ฐจ์
});
๋ ๊น๋ํ๊ฒ ํ๊ณ ์ถ๋ค๋ฉด std::tie๋ฅผ ์ฐ๋ ํธ๋ฆญ๋ ์์ด. ํํ๋ผ๋ฆฌ ์ฌ์ ์ ๋น๊ต๋ฅผ ํด์ฃผ๊ฑฐ๋ .
#include <tuple>
std::sort(s.begin(), s.end(), [](const Student& a, const Student& b) {
return std::tie(b.score, a.name) < std::tie(a.score, b.name);
});
์ ์ ์ชฝ๋ง a, b ์์๋ฅผ ๋ค์ง์ด์ ๋ด๋ฆผ์ฐจ์์ ๋ง๋ ๊ฑฐ์ผ. ์ฒ์์ ํท๊ฐ๋ฆฌ๋๋ฐ ์ต์ํด์ง๋ฉด ์๊ทผ ์ค๋ ๋ผ. ๐ค
๐จ ๊ฐ์ฅ ๋ฌด์์ด ์ง๋ขฐ: Strict Weak Ordering
๋น๊ต ํจ์๋ ์๋ฌด๋ ๊ฒ๋ ์ง๋ฉด ์ ๋ผ. ํ์ค์ ๋น๊ต ํจ์๊ฐ ์๊ฒฉํ ์ฝ์์(strict weak ordering)๋ฅผ ๋ง์กฑํ๋ผ๊ณ ์๊ตฌํด. ์ฝ๊ฒ ๋งํ๋ฉด ์ด๊ฑฐ์ผ:
comp(a, a)๋ ํญ์ falseโก ๋น๋์นญ์ฑ:
comp(a, b)๊ฐ true๋ฉด comp(b, a)๋ falseโข ์ถ์ด์ฑ:
comp(a, b), comp(b, c)๊ฐ true๋ฉด comp(a, c)๋ trueโฃ ๋๋ฑ์ฑ์ ์ถ์ด์ฑ: a์ b๊ฐ ๋๋ฑ, b์ c๊ฐ ๋๋ฑํ๋ฉด a์ c๋ ๋๋ฑ
์ ์ผ ํํ ์ค์๊ฐ return a <= b;์ผ. ์ด๋ฌ๋ฉด comp(a, a)๊ฐ true๊ฐ ๋ผ์ โ ๋ฒ์ ๊นจ๋จ๋ ค. ๊ฒฐ๊ณผ๋? ์ ์๋์ง ์์ ๋์(UB)์ด์ผ. ์ ๋ ฌ์ด ์ด์ํ๊ฒ ๋๊ฑฐ๋, ๊ตฌํ์ ๋ฐ๋ผ ๋ฐฐ์ด ๋ฒ์๋ฅผ ๋์ด ์ฝ๋ค๊ฐ ํ๋ก๊ทธ๋จ์ด ํฐ์ง ์๋ ์์ด. ์ค์ ๋ก ์ฝ๋ฉ ํ
์คํธ์์ "๋ก์ปฌ์์ ๋๋๋ฐ ์ ์ถํ๋ฉด ๋ฐํ์ ์๋ฌ" ๋๋ ๋จ๊ณจ ์์ธ์ด ์ด๊ฑฐ์ผ.
sort์ ์น์ฒ๋ค
| ํจ์ | ํ๋ ์ผ | ๋ณต์ก๋ |
|---|---|---|
| std::sort | ์ ์ฒด ์ ๋ ฌ (๋ถ์์ ) | O(N log N) |
| std::stable_sort | ๊ฐ์ ๊ฐ์ ์๋ ์์ ์ ์ง | ๋ฉ๋ชจ๋ฆฌ ์ถฉ๋ถ ์ O(N log N), ๋ถ์กฑ ์ O(N logยฒ N) |
| std::partial_sort | ์์ชฝ K๊ฐ๋ง ์ ๋ ฌ | ์ฝ O(N log K) |
| std::nth_element | N๋ฒ์งธ ์์๋ง ์ ์๋ฆฌ์ | ํ๊ท O(N) |
| std::is_sorted | ์ ๋ ฌ ์ฌ๋ถ ํ์ธ | O(N) |
์์ ์ ๋ ฌ(stable)์ด ๋ญ๋๋ฉด, ๊ฐ์ด ๊ฐ์ ์์๋ค์ ๊ธฐ์กด ์์๊ฐ ์ ๋ ฌ ํ์๋ ๊ทธ๋๋ก ์ ์ง๋๋ ์ฑ์ง์ด์ผ. std::sort๋ ์ด๊ฑธ ๋ณด์ฅํ์ง ์์. ์๋ฅผ ๋ค์ด "์ด๋ฏธ ์ด๋ฆ์์ผ๋ก ์ ๋ ฌ๋ ๋ฆฌ์คํธ๋ฅผ ์ ์์์ผ๋ก ๋ค์ ์ ๋ ฌํ๋, ๋์ ์๋ ์ด๋ฆ์ ์ ์ง" ๊ฐ์ ์๊ตฌ๋ผ๋ฉด std::stable_sort๊ฐ ์ ๋ต์ด์ผ.
๊ทธ๋ฆฌ๊ณ "์์ 10๋ช
๋ง ํ์ํด!" ๊ฐ์ ์ํฉ์์ ๋ฐฑ๋ง ๊ฐ ์ ์ฒด๋ฅผ ์ ๋ ฌํ๋ ๊ฑด ๋ญ๋น์ผ. ์ด๋ด ๋ partial_sort, ์ค์๊ฐ ํ๋๋ง ํ์ํ๋ฉด nth_element. ๋๊ตฌ๋ฅผ ์ํฉ์ ๋ง๊ฒ ๊ณ ๋ฅด๋ ๊ฒ ์ง์ง ๊ณ ์์ ๊ฐ๊ฐ์ด์ง.
std::vector<int> v = {9, 4, 7, 1, 8, 2, 6};
std::partial_sort(v.begin(), v.begin() + 3, v.end()); // ์ 3๊ฐ: 1 2 4 (๋๋จธ์ง๋ ์์ ๋ฏธ์ )
std::nth_element(v.begin(), v.begin() + v.size()/2, v.end());
int median = v[v.size()/2]; // ์ค์๊ฐ 6
๐ 2. std::find โ ์ฐพ์๋ผ, ๊ทธ ์์๋ฅผ!
๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
std::find๋ ๋ฒ์๋ฅผ ์์์๋ถํฐ ์์๋๋ก ํ์ผ๋ฉด์ ๊ฐ์ด ๊ฐ์(==) ์ฒซ ๋ฒ์งธ ์์์ ๋ฐ๋ณต์๋ฅผ ๋๋ ค์ค. ๋ชป ์ฐพ์ผ๋ฉด? last๋ฅผ ๋๋ ค์ค. nullptr๋ -1๋ ์๋์ผ. ์ด๊ฒ ์ง์ง ์ค์ํด!
std::vector<int> v = {3, 8, 5, 1, 5};
auto it = std::find(v.begin(), v.end(), 5);
if (it != v.end()) {
std::cout << "์ฐพ์! ์ธ๋ฑ์ค: " << std::distance(v.begin(), it); // 2
} else {
std::cout << "์์";
}
๋ฐ๋ณต์์์ ์ธ๋ฑ์ค๋ฅผ ์ป๊ณ ์ถ์ ๋ std::distance(v.begin(), it) ๋๋ vector์ฒ๋ผ ๋๋ค ์ก์ธ์ค๋ผ๋ฉด it - v.begin()์ ์ฐ๋ฉด ๋ผ.
*it๋ฅผ ์ญ์ฐธ์กฐํ๋ ๊ฒ. end()๋ฅผ ์ญ์ฐธ์กฐํ๋ ๊ฑด UB์ผ. "์ฐพ์๊ฒ ์ง~" ํ๋ ์๊ฐ ๋ฒ๊ทธ๊ฐ ์ฐพ์์จ๋ค. ๐ฑfind์ ๊ฐ์กฑ: find_if, find_if_not
"ํน์ ๊ฐ"์ด ์๋๋ผ "์กฐ๊ฑด"์ผ๋ก ์ฐพ๊ณ ์ถ์ ๋๊ฐ ๋ ๋ง์์? ๊ทธ๋ด ๋ find_if์ผ.
// ์ฒซ ๋ฒ์งธ ์ง์ ์ฐพ๊ธฐ
auto it = std::find_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; });
// ์ ์ 90์ ์ด์์ธ ์ฒซ ํ์ ์ฐพ๊ธฐ
auto st = std::find_if(s.begin(), s.end(),
[](const Student& a) { return a.score >= 90; });
// ์กฐ๊ฑด์ ๋ง์กฑํ์ง "์๋" ์ฒซ ์์ (C++11)
auto it2 = std::find_if_not(v.begin(), v.end(), [](int x) { return x > 0; });
์ฐธ๊ณ ๋ก ๋จ์ํ "์๋ ์๋"๋ง ๊ถ๊ธํ๋ฉด std::any_of, std::all_of, std::none_of๊ฐ ์๋๋ฅผ ๋ ์ ๋๋ฌ๋ด. ๊ฐ์๊ฐ ๊ถ๊ธํ๋ฉด std::count / std::count_if.
์ฑ๋ฅ ํฉํธ: find๋ ์ธ์ ์ฐ๋ฉด ์ ๋ ๊น?
std::find๋ ์ ํ ํ์์ด๋ผ ์ต๋ N๋ฒ ๋น๊ตํด. ์ฆ O(N). ์์๊ฐ ๋ช ๊ฐ ์ ๋๊ฑฐ๋ ํ๋ ๋ฒ๋ง ์ฐพ์ ๋ ์ด๊ฒ ์ต๊ณ ์ผ. ๊ทผ๋ฐ ํฐ ๋ฐ์ดํฐ์์ ๋ฐ๋ณต์ ์ผ๋ก ๊ฒ์ํด์ผ ํ๋ค๋ฉด ์๊ธฐ๊ฐ ๋ฌ๋ผ์ ธ.
๋ฐฑ๋ง ๊ฐ๋ฉด logโ(1,000,000) โ 19.9๋๊น ์ด์ง ํ์์ ์ฝ 20๋ฒ์ด๋ฉด ๋๋. ์ฐจ์ด๊ฐ ์์ฒญ๋์ง? ๊ทธ๋์ ์ํฉ๋ณ๋ก ์ด๋ ๊ฒ ๊ณจ๋ผ ์จ.
std::find
O(N). ์ค๋น ๋น์ฉ 0. ๊ฐ์ฅ ๊ฐ๋จ.
binary_search / lower_bound
O(log N). ๋จ, ๋ฏธ๋ฆฌ ์ ๋ ฌ(O(N log N)) ํ์.
std::set / unordered_set
set์ O(log N), unordered_set์ ํ๊ท O(1).
std::sort(v.begin(), v.end());
bool exists = std::binary_search(v.begin(), v.end(), 5); // true/false๋ง ๋ฐํ
auto lb = std::lower_bound(v.begin(), v.end(), 5); // 5 ์ด์์ธ ์ฒซ ์์น
auto ub = std::upper_bound(v.begin(), v.end(), 5); // 5 ์ด๊ณผ์ธ ์ฒซ ์์น
auto cnt = ub - lb; // 5์ ๊ฐ์
std::set์ด๋ std::map์์๋ std::find(s.begin(), s.end(), x) ๋ง๊ณ ๋ฉค๋ฒ ํจ์ s.find(x)๋ฅผ ์จ! ์ ์ญ std::find๋ O(N)์ผ๋ก ๋ค ํ์ง๋ง, ๋ฉค๋ฒ find๋ ํธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ํ์ฉํด O(log N)์ด์ผ. C++20๋ถํฐ๋ s.contains(x)๋ ์์ด์ ์กด์ฌ ์ฌ๋ถ ํ์ธ์ด ๋ ๊น๋ํด์ก๊ณ .๋ฌธ์์ด์์๋ ์ธ ์ ์์ด
std::string str = "hello world";
auto it = std::find(str.begin(), str.end(), 'w'); // 'w' ์์น
// ๋ถ๋ถ ๋ฌธ์์ด ๊ฒ์์ std::string::find ๋ฉค๋ฒ๋ std::search๊ฐ ์ ํฉ
๐ 3. std::transform โ ๋ฐ์ดํฐ ๋ณ์ ๊ณต์ฅ
๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ (๋จํญ ๋ฒ์ )
std::transform์ ๋ฒ์์ ๊ฐ ์์์ ํจ์๋ฅผ ์ ์ฉํด์ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅ ์์น์ ์จ. ํจ์ํ ์ธ์ด์ map์ด๋ ๊ฐ์ ๊ฐ๋
์ด์ผ. ํ์ด์ฌ์ map()์ด๋ ์๋ฐ์คํฌ๋ฆฝํธ์ array.map() ์จ๋ดค์ผ๋ฉด ๋ฐ๋ก ๊ฐ ์ฌ ๊ฑฐ์ผ.
std::vector<int> v = {1, 2, 3, 4};
std::vector<int> out(v.size()); // ํฌ๊ธฐ๋ฅผ ๋ฏธ๋ฆฌ ํ๋ณด!
std::transform(v.begin(), v.end(), out.begin(),
[](int x) { return x * x; }); // out = 1 4 9 16
๋ฐํ๊ฐ์ ๋ง์ง๋ง์ผ๋ก ์ด ์์ ๋ค์ ์์น์ ์ถ๋ ฅ ๋ฐ๋ณต์์ผ. ์ด์ด์ ๋ญ๊ฐ๋ฅผ ๋ ์ฐ๊ณ ์ถ์ ๋ ์ ์ฉํด.
๐จ ์ง๋ขฐ: ์ถ๋ ฅ ๊ณต๊ฐ ํ๋ณด
์ ์ผ ๋ง์ด ํ๋ ์ค์๊ฐ ์ด๊ฑฐ์ผ.
std::vector<int> out; // ๋น์ด ์์!
std::transform(v.begin(), v.end(), out.begin(), f); // โ UB! ๋น ๊ณต๊ฐ์ ์ฐ๊ธฐ
transform์ ๊ณต๊ฐ์ ์์์ ๋๋ ค์ฃผ์ง ์์. ๊ทธ๋ฅ ์ฃผ์ด์ง ์์น์ ๋ฎ์ด์ธ ๋ฟ์ด์ผ. ํด๊ฒฐ์ฑ
์ ๋ ๊ฐ์ง.
// ๋ฐฉ๋ฒ 1: ํฌ๊ธฐ ๋ฏธ๋ฆฌ ํ๋ณด
std::vector<int> out(v.size());
std::transform(v.begin(), v.end(), out.begin(), f);
// ๋ฐฉ๋ฒ 2: back_inserter๋ก push_back ํ๊ฒ ๋ง๋ค๊ธฐ
#include <iterator>
std::vector<int> out2;
out2.reserve(v.size()); // ์ฌํ ๋น ์ค์ด๊ธฐ์ฉ (์ ํ)
std::transform(v.begin(), v.end(), std::back_inserter(out2), f);
์ ์๋ฆฌ ๋ณํ (in-place)
์ถ๋ ฅ ์์น๋ฅผ ์ ๋ ฅ์ ์์์ผ๋ก ์ฃผ๋ฉด ์๋ณธ์ ๊ทธ๋๋ก ๋ฎ์ด์ธ ์ ์์ด. ํ์ค์ด ์ด๊ฑธ ๋ช ์์ ์ผ๋ก ํ์ฉํด.
std::transform(v.begin(), v.end(), v.begin(), [](int x) { return x * 2; });
์ดํญ ๋ฒ์ : ๋ ๋ฒ์๋ฅผ ํฉ์น๊ธฐ
์ ๋ ฅ ๋ฒ์๋ฅผ ๋ ๊ฐ ๋ฐ์์ ์์ ์๋ง๋ค ํจ์๋ฅผ ์ ์ฉํ๋ ๋ฒ์ ๋ ์์ด.
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {10, 20, 30};
std::vector<int> out(a.size());
std::transform(a.begin(), a.end(), b.begin(), out.begin(), std::plus<>());
// out = 11 22 33
์ค์ ์์ : ๋ฌธ์์ด ๋์๋ฌธ์ ๋ณํ
์ด๊ฑฐ ์ง์ง ์์ฃผ ์ฐ๋๋ฐ, ์จ์ ํจ์ ์ด ํ๋ ์์ด.
#include <cctype>
std::string s = "Hello STL";
// โ ์ํํ ์ ์์
// std::transform(s.begin(), s.end(), s.begin(), ::toupper);
// โ
์์ ํ ๋ฐฉ๋ฒ
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return std::toupper(c); });
์ ๊ตณ์ด unsigned char๋ก ๋ฐ๋๊ณ ? std::toupper๋ ์ธ์๊ฐ unsigned char๋ก ํํ ๊ฐ๋ฅํ ๊ฐ์ด๊ฑฐ๋ EOF์ฌ์ผ ํ๋ค๊ณ ๊ท์ ๋ผ ์์ด. ๊ทธ๋ฐ๋ฐ char๊ฐ signed์ธ ํ๊ฒฝ(x86์ ๋๋ถ๋ถ ์ปดํ์ผ๋ฌ๊ฐ ๊ทธ๋)์์ ํ๊ธ ๊ฐ์ ๋ฉํฐ๋ฐ์ดํธ ๋ฌธ์์ ๋ฐ์ดํธ๋ ์์๊ฐ ๋ ์ ์๊ณ , ๊ทธ๊ฑธ ๊ทธ๋๋ก ๋๊ธฐ๋ฉด UB์ผ. ๊ฒ๋ค๊ฐ std::toupper๋ <locale>์ ์ค๋ฒ๋ก๋๊ฐ ์์ด์ ํจ์ ์ด๋ฆ๋ง ๋๊ธฐ๋ฉด ๋ชจํธ์ฑ ์ปดํ์ผ ์๋ฌ๊ฐ ๋ ๋๋ ์๊ณ . ๋๋ค๋ก ๊ฐ์ธ๋ฉด ๋ ๋ฌธ์ ๊ฐ ํ ๋ฒ์ ํด๊ฒฐ๋ผ. ๐
ํ์ ๋ณํ๋ ์์ ์์ฌ
std::vector<int> nums = {1, 2, 3};
std::vector<std::string> strs;
std::transform(nums.begin(), nums.end(), std::back_inserter(strs),
[](int n) { return "#" + std::to_string(n); });
// strs = "#1" "#2" "#3"
// ๊ตฌ์กฐ์ฒด์์ ํน์ ํ๋๋ง ๋ฝ๊ธฐ
std::vector<std::string> names;
std::transform(s_list.begin(), s_list.end(), std::back_inserter(names),
[](const Student& st) { return st.name; });
std::for_each๊ฐ ์๋๋ฅผ ๋ ์ ๋๋ฌ๋ด. ๊ทธ๋ฆฌ๊ณ ํ์ค์ transform์ ๋๊ธด ํจ์๊ฐ ์์๋๋ก ํธ์ถ๋๋ค๊ณ ๋ณด์ฅํ์ง ์์ผ๋ ๋ถ์ํจ๊ณผ(side effect)์ ์์กดํ๋ ์ฝ๋๋ ํผํ์.๐งฉ ์ธ ๋ ์ ํฉ์ฒด! ์ค์ ๋ฏธ๋ ํ๋ก์ ํธ
์ด์ ๋ฐฐ์ด ๊ฑธ ํ ๋ฒ์ ์จ๋ณด์. ์ํฉ: ์ผํ๋ชฐ ์ํ ๋ชฉ๋ก์์ ๊ฐ๊ฒฉ์ ํ ์ธ์จ ์ ์ฉ โ ๊ฐ๊ฒฉ์ ์ ๋ ฌ โ ํน์ ์ํ ์ฐพ๊ธฐ.
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
struct Item {
std::string name;
double price;
};
int main() {
std::vector<Item> items = {
{"ํค๋ณด๋", 50000}, {"๋ง์ฐ์ค", 20000},
{"๋ชจ๋ํฐ", 200000}, {"ํค๋์
", 80000}
};
// 1) transform: ์ ์ํ 10% ํ ์ธ (์ ์๋ฆฌ ๋ณํ)
std::transform(items.begin(), items.end(), items.begin(),
[](Item it) { it.price *= 0.9; return it; });
// 2) sort: ๊ฐ๊ฒฉ ์ค๋ฆ์ฐจ์
std::sort(items.begin(), items.end(),
[](const Item& a, const Item& b) { return a.price < b.price; });
// 3) find_if: 10๋ง ์ ์ด์์ธ ์ฒซ ์ํ
auto it = std::find_if(items.begin(), items.end(),
[](const Item& i) { return i.price >= 100000; });
if (it != items.end())
std::cout << "๊ณ ๊ฐ ์ฒซ ์ํ: " << it->name << " (" << it->price << "์)\n";
// ์ถ๋ ฅ: ๊ณ ๊ฐ ์ฒซ ์ํ: ๋ชจ๋ํฐ (180000์)
}
์ฐธ๊ณ ๋ก ์ ๋ ฌ๋ ๋ฐ์ดํฐ๋๊น 3๋ฒ์ std::partition_point๋ lower_bound๋ก O(log N)์ ์ฐพ์ ์๋ ์์ด. ์ด๋ ๊ฒ "์ ๋จ๊ณ ๊ฒฐ๊ณผ๋ฅผ ํ์ฉํด ๋ค์ ๋จ๊ณ ์๊ณ ๋ฆฌ์ฆ์ ๊ณ ๋ฅด๋" ๊ฐ๊ฐ์ด ์์ด๋ฉด ์ฝ๋ ๋ฆฌ๋ทฐ์์ ์นญ์ฐฌ๋ฐ๋ ๊ฑฐ์ผ. ๐
๐ C++20 Ranges: ๋ ์งง๊ณ ๋ ์์ ํ๊ฒ
C++20๋ถํฐ๋ std::ranges ๋ค์์คํ์ด์ค์ ๋ฒ์ ๊ธฐ๋ฐ ์๊ณ ๋ฆฌ์ฆ์ด ์ถ๊ฐ๋์ด. begin(), end()๋ฅผ ์ผ์ผ์ด ์ ์จ๋ ๋๊ณ , ํ๋ก์ ์
(projection)์ด๋ผ๋ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ๋ ์๊ฒผ์ด.
#include <algorithm>
#include <ranges>
std::ranges::sort(v); // ๋ฒ์ ํต์งธ๋ก
std::ranges::sort(items, {}, &Item::price); // ํ๋ก์ ์
: price ๊ธฐ์ค ์ ๋ ฌ
auto it = std::ranges::find(items, "๋ง์ฐ์ค", &Item::name); // name ํ๋๋ก ๊ฒ์
// views๋ก ์ง์ฐ ํ๊ฐ ํ์ดํ๋ผ์ธ
auto evens_squared = v
| std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * x; });
ํ๋ก์ ์
๋๋ถ์ "๊ฐ๊ฒฉ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌ" ๊ฐ์ ๊ฑธ ๋๋ค ์์ด &Item::price ํ๋๋ก ๋๋ผ ์ ์์ด. ๋ ranges ์๊ณ ๋ฆฌ์ฆ์ ์ฝ์
ํธ(concepts)๋ก ์ ์ฝ์ด ๊ฑธ๋ ค ์์ด์ list์ sort๋ฅผ ์ฐ๋ ์ค์๋ฅผ ํ๋ฉด ํจ์ฌ ์ฝ๊ธฐ ์ฌ์ด ์๋ฌ๊ฐ ๋์. ๊ทธ๋ฆฌ๊ณ views::transform์ ์ฆ์ ๊ณ์ฐํ์ง ์๊ณ ๊ฐ์ ๊บผ๋ผ ๋ ๊ณ์ฐ(์ง์ฐ ํ๊ฐ)ํ๋ค๋ ์ ์ด std::transform๊ณผ์ ํฐ ์ฐจ์ด์ผ.
โก ๋ณด๋์ค: ๋ณ๋ ฌ ์คํ ์ ์ฑ (C++17)
C++17๋ถํฐ ๋ง์ ์๊ณ ๋ฆฌ์ฆ์ด ์คํ ์ ์ฑ ์ ์ฒซ ์ธ์๋ก ๋ฐ์ ์ ์์ด.
#include <execution>
std::sort(std::execution::par, v.begin(), v.end());
std::transform(std::execution::par_unseq, v.begin(), v.end(), v.begin(), f);
seq(์์ฐจ), par(๋ณ๋ ฌ), par_unseq(๋ณ๋ ฌ+๋ฒกํฐํ)๊ฐ ์๊ณ , C++20์์ unseq๊ฐ ์ถ๊ฐ๋์ด. ๋จ, ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด ์ค๋ ๋ ๊ด๋ฆฌ ๋น์ฉ ๋๋ฌธ์ ์คํ๋ ค ๋๋ ค์ง ์ ์๊ณ , ํจ์ ์์์ ๊ณต์ ๋ฐ์ดํฐ๋ฅผ ๊ฑด๋๋ฆฌ๋ฉด ๋ฐ์ดํฐ ๋ ์ด์ค๊ฐ ์๊ธฐ๋ ์กฐ์ฌํด. GCC์์ ๊ตฌํ์ ๋ฐ๋ผ Intel TBB ๋งํฌ(-ltbb)๊ฐ ํ์ํ ์ ์์ด.
๐ ํ๋์ ์ ๋ฆฌ
โข ๋๋ค ์ก์ธ์ค ๋ฐ๋ณต์ ํ์
โข C++11๋ถํฐ ์ต์ O(N log N)
โข ๋ถ์์ โ ํ์ํ๋ฉด stable_sort
โข ๋น๊ต๋ < ๋๋ >๋ง!
โข ์ ํ ํ์ O(N)
โข ๋ชป ์ฐพ์ผ๋ฉด last ๋ฐํ
โข ์กฐ๊ฑด ๊ฒ์์ find_if
โข set/map์ ๋ฉค๋ฒ find
โข ๋จํญ/์ดํญ ๋ ๋ฒ์
โข ์ถ๋ ฅ ๊ณต๊ฐ ์ง์ ํ๋ณด
โข back_inserter ํ์ฉ
โข ์ ์๋ฆฌ ๋ณํ ๊ฐ๋ฅ
๐ฏ ๋ง๋ฌด๋ฆฌ ํ๋ง๋STL ์๊ณ ๋ฆฌ์ฆ์ ์ฐ๋ฉด ์ฝ๋๊ฐ ์งง์์ง๋ ๊ฒ ์ด์์ ์ด๋์ด ์์ด. std::find_if๋ผ๋ ์ด๋ฆ ์์ฒด๊ฐ "์กฐ๊ฑด์ ๋ง๋ ๊ฑธ ์ฐพ๋๋ค"๋ ์๋๋ฅผ ๋ฌธ์์ฒ๋ผ ๋๋ฌ๋ด๊ฑฐ๋ . ์์ผ๋ก ์ง for๋ฌธ์ ์ฝ๋ ์ฌ๋์ด ํ ์ค์ฉ ํด์ํด์ผ ํ์ง๋ง, ์๊ณ ๋ฆฌ์ฆ ์ด๋ฆ์ ํ ๋ฒ์ ์ฝํ. ๊ฒ๋ค๊ฐ ์๋ง์ ๊ฐ๋ฐ์๊ฐ ๊ฒ์ฆํ ๊ตฌํ์ด๋ผ ๋ฒ๊ทธ ๊ฑฑ์ ๋ ์ค๊ณ .
์ด๋ฐ C++ ์ค๋ ฅ์ ์ฝ๋ฉ ํ
์คํธ, ๊ฒ์ ์์ง, ๊ธ์ต ์์คํ
, ์๋ฒ ๋๋ ๋ฑ ์ฑ๋ฅ์ด ์ค์ํ ๋ถ์ผ ์ด๋์๋ ํตํด. ์ฌ๋ฅ๋ท ๊ฐ์ ์ฌ๋ฅ ๊ฑฐ๋ ํ๋ซํผ์์๋ C++ ๊ณผ์ธ๋ ์ฝ๋ ๋ฆฌ๋ทฐ, ์๊ณ ๋ฆฌ์ฆ ๋ฌธ์ ํ์ด ๋ฉํ ๋ง์ฒ๋ผ ์ด ์ง์์ ๋ฐ๋ก ๋๋ ์ ์๋ ๊ธฐํ๊ฐ ๋ง์ผ๋, ์ค๋ ๋ฐฐ์ด 3๋์ฅ์ ๊ผญ ์์ ์ตํ๋์๊ณ ! ๐ช
๐ ์ฐธ๊ณ ์๋ฃ
โข cppreference โ std::sort: https://en.cppreference.com/w/cpp/algorithm/sort
โข cppreference โ std::find, std::find_if: https://en.cppreference.com/w/cpp/algorithm/find
โข cppreference โ std::transform: https://en.cppreference.com/w/cpp/algorithm/transform
โข cppreference โ Named requirements: Compare: https://en.cppreference.com/w/cpp/named_req/Compare
โข cppreference โ std::toupper: https://en.cppreference.com/w/cpp/string/byte/toupper
โข cppreference โ Constrained algorithms (C++20): https://en.cppreference.com/w/cpp/algorithm/ranges
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.