STL 알고리즘
2025. 3. 28. 08:54ㆍProgramming Languages/C++
8.4 STL 알고리즘
STL 알고리즘은 컨테이너의 요소를 처리하는 다양한 함수를 제공합니다.
8.4.1 비수정 시퀀스 연산
요소를 수정하지 않고 조사하는 알고리즘:
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric> // accumulate
// 홀수 여부 판별 함수
bool isOdd(int n) {
return n % 2 != 0;
}
int main() {
std::vector<int> vec = {5, 7, 3, 1, 9, 2, 8, 4, 6};
// all_of: 모든 요소가 조건을 만족하는지 확인
bool allOdd = std::all_of(vec.begin(), vec.end(), isOdd);
std::cout << "모든 요소가 홀수인가? " << std::boolalpha << allOdd << std::endl;
// any_of: 적어도 하나의 요소가 조건을 만족하는지 확인
bool anyOdd = std::any_of(vec.begin(), vec.end(), isOdd);
std::cout << "홀수가 있는가? " << anyOdd << std::endl;
// none_of: 모든 요소가 조건을 만족하지 않는지 확인
bool noneOdd = std::none_of(vec.begin(), vec.end(), isOdd);
std::cout << "홀수가 없는가? " << noneOdd << std::endl;
// for_each: 각 요소에 함수 적용
std::cout << "모든 요소: ";
std::for_each(vec.begin(), vec.end(), [](int n) {
std::cout << n << " ";
});
std::cout << std::endl;
// find: 특정 값 찾기
auto it = std::find(vec.begin(), vec.end(), 9);
if (it != vec.end()) {
std::cout << "9의 위치: " << std::distance(vec.begin(), it) << std::endl;
}
// find_if: 조건을 만족하는 첫 번째 요소 찾기
auto it2 = std::find_if(vec.begin(), vec.end(), [](int n) {
return n > 5;
});
if (it2 != vec.end()) {
std::cout << "5보다 큰 첫 번째 요소: " << *it2 << std::endl;
}
// count: 특정 값의 개수 세기
int count1 = std::count(vec.begin(), vec.end(), 1);
std::cout << "1의 개수: " << count1 << std::endl;
// count_if: 조건을 만족하는 요소의 개수 세기
int oddCount = std::count_if(vec.begin(), vec.end(), isOdd);
std::cout << "홀수의 개수: " << oddCount << std::endl;
// equal: 두 범위가 같은지 비교
std::vector<int> vec2 = vec;
bool areEqual = std::equal(vec.begin(), vec.end(), vec2.begin());
std::cout << "vec와 vec2가 같은가? " << areEqual << std::endl;
// accumulate: 범위 내 요소의 합계 계산
int sum = std::accumulate(vec.begin(), vec.end(), 0);
std::cout << "모든 요소의 합: " << sum << std::endl;
// 사용자 정의 누적 함수
int product = std::accumulate(vec.begin(), vec.end(), 1,
[](int acc, int val) { return acc * val; });
std::cout << "모든 요소의 곱: " << product << std::endl;
return 0;
}
8.4.2 수정 시퀀스 연산
요소를 수정하는 알고리즘:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = {5, 7, 3, 1, 9, 2, 8, 4, 6};
// copy: 범위를 다른 범위로 복사
std::vector<int> vec2(vec.size());
std::copy(vec.begin(), vec.end(), vec2.begin());
std::cout << "vec2 (copy): ";
for (const auto& elem : vec2) {
std::cout << elem << " ";
}
std::cout << std::endl;
// copy_if: 조건을 만족하는 요소만 복사
std::vector<int> vec3;
std::copy_if(vec.begin(), vec.end(), std::back_inserter(vec3),
[](int n) { return n % 2 == 0; }); // 짝수만 복사
std::cout << "vec3 (짝수만): ";
for (const auto& elem : vec3) {
std::cout << elem << " ";
}
std::cout << std::endl;
// transform: 각 요소에 함수를 적용하여 결과를 저장
std::vector<int> vec4(vec.size());
std::transform(vec.begin(), vec.end(), vec4.begin(),
[](int n) { return n * 2; }); // 각 요소를 2배로
std::cout << "vec4 (2배): ";
for (const auto& elem : vec4) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 두 범위를 조합하는 transform
std::vector<int> vec5 = {10, 20, 30, 40, 50, 60, 70, 80, 90};
std::vector<int> vec6(vec.size());
std::transform(vec.begin(), vec.end(), vec5.begin(), vec6.begin(),
[](int a, int b) { return a + b; }); // 두 벡터의 대응하는 요소 합
std::cout << "vec6 (vec + vec5): ";
for (const auto& elem : vec6) {
std::cout << elem << " ";
}
std::cout << std::endl;
// replace: 특정 값을 다른 값으로 대체
std::replace(vec2.begin(), vec2.end(), 9, 99);
std::cout << "vec2 (9를 99로 대체): ";
for (const auto& elem : vec2) {
std::cout << elem << " ";
}
std::cout << std::endl;
// replace_if: 조건을 만족하는 요소를 대체
std::replace_if(vec2.begin(), vec2.end(),
[](int n) { return n < 5; }, // 5보다 작은 요소를
0); // 0으로 대체
std::cout << "vec2 (5 미만을 0으로 대체): ";
for (const auto& elem : vec2) {
std::cout << elem << " ";
}
std::cout << std::endl;
// fill: 범위를 특정 값으로 채움
std::fill(vec2.begin(), vec2.begin() + 3, 100);
std::cout << "vec2 (처음 3개를 100으로): ";
for (const auto& elem : vec2) {
std::cout << elem << " ";
}
std::cout << std::endl;
// generate: 함수 호출 결과로 범위를 채움
int value = 1;
std::generate(vec2.begin(), vec2.end(), [&value]() {
return value++; // 1부터 시작하는 연속된 값
});
std::cout << "vec2 (연속된 값): ";
for (const auto& elem : vec2) {
std::cout << elem << " ";
}
std::cout << std::endl;
// remove: 특정 값을 제거 (실제로 컨테이너 크기는 변경되지 않음)
auto new_end = std::remove(vec2.begin(), vec2.end(), 5);
std::cout << "vec2 (5 제거 후, 논리적 끝까지만): ";
for (auto it = vec2.begin(); it != new_end; ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// remove_if: 조건을 만족하는 요소 제거
new_end = std::remove_if(vec2.begin(), vec2.end(),
[](int n) { return n % 2 == 0; }); // 짝수 제거
// erase-remove 관용구: 실제로 컨테이너에서 제거
vec2.erase(new_end, vec2.end());
std::cout << "vec2 (짝수 제거 후): ";
for (const auto& elem : vec2) {
std::cout << elem << " ";
}
std::cout << std::endl;
// unique: 연속된 중복 요소 제거
std::vector<int> vec7 = {1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5, 5};
auto unique_end = std::unique(vec7.begin(), vec7.end());
vec7.erase(unique_end, vec7.end());
std::cout << "vec7 (중복 제거 후): ";
for (const auto& elem : vec7) {
std::cout << elem << " ";
}
std::cout << std::endl;
// reverse: 범위의 요소 순서를 뒤집음
std::reverse(vec.begin(), vec.end());
std::cout << "vec (뒤집은 후): ";
for (const auto& elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
// rotate: 범위의 요소를 회전
std::rotate(vec.begin(), vec.begin() + 3, vec.end());
std::cout << "vec (3칸 회전 후): ";
for (const auto& elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
// shuffle: 범위의 요소 무작위 섞기
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(vec.begin(), vec.end(), g);
std::cout << "vec (섞은 후): ";
for (const auto& elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
8.4.3 정렬 연산
요소를 정렬하는 알고리즘:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional> // std::greater
#include <string>
struct Person {
std::string name;
int age;
// 비교를 위한 연산자 오버로딩
bool operator<(const Person& other) const {
return age < other.age; // 나이로 오름차순 정렬
}
};
int main() {
std::vector<int> vec = {5, 7, 3, 1, 9, 2, 8, 4, 6};
// sort: 기본 정렬 (오름차순)
std::sort(vec.begin(), vec.end());
std::cout << "vec (오름차순 정렬): ";
for (const auto& elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 내림차순 정렬
std::sort(vec.begin(), vec.end(), std::greater<int>());
std::cout << "vec (내림차순 정렬): ";
for (const auto& elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 사용자 정의 비교 함수 사용
std::sort(vec.begin(), vec.end(), [](int a, int b) {
return (a % 2) < (b % 2); // 짝수가 홀수보다 앞에 오도록
});
std::cout << "vec (짝수 먼저 정렬): ";
for (const auto& elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
// partial_sort: 일부만 정렬
std::vector<int> vec2 = {5, 7, 3, 1, 9, 2, 8, 4, 6};
std::partial_sort(vec2.begin(), vec2.begin() + 4, vec2.end());
std::cout << "vec2 (앞 4개만 정렬): ";
for (const auto& elem : vec2) {
std::cout << elem << " ";
}
std::cout << std::endl;
// stable_sort: 동일한 값의 상대적 순서 유지
std::vector<Person> people = {
{"Alice", 25},
{"Bob", 30},
{"Charlie", 25},
{"David", 20}
};
std::stable_sort(people.begin(), people.end());
std::cout << "people (나이순 안정 정렬):" << std::endl;
for (const auto& person : people) {
std::cout << " " << person.name << ": " << person.age << std::endl;
}
// nth_element: n번째 요소를 찾아 배치
std::vector<int> vec3 = {5, 7, 3, 1, 9, 2, 8, 4, 6};
std::nth_element(vec3.begin(), vec3.begin() + 4, vec3.end());
std::cout << "vec3 (5번째 요소 찾기): ";
for (const auto& elem : vec3) {
std::cout << elem << " ";
}
std::cout << std::endl;
std::cout << "5번째 요소: " << vec3[4] << std::endl;
// is_sorted: 정렬 여부 확인
bool sorted = std::is_sorted(vec.begin(), vec.end());
std::cout << "vec가 정렬되어 있는가? " << std::boolalpha << sorted << std::endl;
// binary_search: 정렬된 범위에서 값 찾기 (이진 검색)
std::sort(vec.begin(), vec.end()); // 이진 검색 전에 정렬 필요
bool found = std::binary_search(vec.begin(), vec.end(), 7);
std::cout << "7을 찾았는가? " << found << std::endl;
// lower_bound와 upper_bound: 정렬된 범위에서 값의 경계 찾기
auto lower = std::lower_bound(vec.begin(), vec.end(), 5); // 5 이상인 첫 번째 요소
auto upper = std::upper_bound(vec.begin(), vec.end(), 5); // 5보다 큰 첫 번째 요소
std::cout << "5 이상인 첫 번째 요소: " << *lower << std::endl;
std::cout << "5보다 큰 첫 번째 요소: " << *upper << std::endl;
// 값의 범위 계산
auto range = std::equal_range(vec.begin(), vec.end(), 5);
std::cout << "5의 범위: " << std::distance(range.first, range.second) << std::endl;
// merge: 두 정렬된 범위 병합
std::vector<int> vec4 = {1, 3, 5, 7, 9};
std::vector<int> vec5 = {2, 4, 6, 8, 10};
std::vector<int> vec6(vec4.size() + vec5.size());
std::merge(vec4.begin(), vec4.end(), vec5.begin(), vec5.end(), vec6.begin());
std::cout << "vec6 (병합 결과): ";
for (const auto& elem : vec6) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}
8.4.4 수치 연산
수치 계산을 위한 알고리즘:
#include <iostream>
#include <vector>
#include <numeric>
#include <cmath>
#include <iomanip> // std::setprecision
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// accumulate: 합계 계산
int sum = std::accumulate(vec.begin(), vec.end(), 0);
std::cout << "합계: " << sum << std::endl;
// 사용자 정의 합계 함수
int sum_squares = std::accumulate(vec.begin(), vec.end(), 0,
[](int acc, int val) {
return acc + val * val;
});
std::cout << "제곱의 합: " << sum_squares << std::endl;
// inner_product: 내적 계산
std::vector<int> vec2 = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
int dot_product = std::inner_product(vec.begin(), vec.end(), vec2.begin(), 0);
std::cout << "내적: " << dot_product << std::endl;
// 사용자 정의 내적 함수
int custom_product = std::inner_product(vec.begin(), vec.end(), vec2.begin(), 0,
std::plus<int>(), // 외부 연산 (합계)
[](int a, int b) { // 내부 연산 (곱셈 대신)
return a * (b / 10); // vec2의 각 요소를 10으로 나눈 후 곱
});
std::cout << "사용자 정의 내적: " << custom_product << std::endl;
// adjacent_difference: 인접 요소 간의 차이 계산
std::vector<int> diffs(vec.size());
std::adjacent_difference(vec.begin(), vec.end(), diffs.begin());
std::cout << "인접 차이: ";
for (const auto& elem : diffs) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 사용자 정의 인접 차이 함수 (합계 대신)
std::vector<int> diffs2(vec.size());
std::adjacent_difference(vec.begin(), vec.end(), diffs2.begin(),
[](int a, int b) { return a + b; }); // 차이 대신 합계
std::cout << "인접 합계: ";
for (const auto& elem : diffs2) {
std::cout << elem << " ";
}
std::cout << std::endl;
// partial_sum: 부분합 계산
std::vector<int> partial_sums(vec.size());
std::partial_sum(vec.begin(), vec.end(), partial_sums.begin());
std::cout << "부분합: ";
for (const auto& elem : partial_sums) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 사용자 정의 부분합 함수 (곱으로)
std::vector<int> partial_products(vec.size());
std::partial_sum(vec.begin(), vec.end(), partial_products.begin(),
std::multiplies<int>()); // 합계 대신 곱
std::cout << "부분곱: ";
for (const auto& elem : partial_products) {
std::cout << elem << " ";
}
std::cout << std::endl;
// iota: 연속된 값 생성
std::vector<int> sequence(10);
std::iota(sequence.begin(), sequence.end(), 1); // 1부터 시작
std::cout << "연속된 값: ";
for (const auto& elem : sequence) {
std::cout << elem << " ";
}
std::cout << std::endl;
// 통계 계산 (C++17에서는 <numeric> 헤더에 함수가 추가됨)
// 여기서는 수동으로 계산
// 평균
double mean = static_cast<double>(sum) / vec.size();
std::cout << "평균: " << mean << std::endl;
// 분산
double variance = 0.0;
for (int val : vec) {
variance += (val - mean) * (val - mean);
}
variance /= vec.size();
// 표준 편차
double stddev = std::sqrt(variance);
std::cout << "분산: " << std::fixed << std::setprecision(2) << variance << std::endl;
std::cout << "표준 편차: " << stddev << std::endl;
return 0;
}
'Programming Languages > C++' 카테고리의 다른 글
챕터8. 실습 문제 (0) | 2025.03.28 |
---|---|
함수 객체와 람다 표현식 (0) | 2025.03.28 |
STL 반복자 (0) | 2025.03.28 |
STL 컨테이너 (0) | 2025.03.28 |
STL (Standard Template Library) (0) | 2025.03.28 |