[Basic C++] #50-1_STL 알고리즘, 변경 순차 알고리즘, transform(), copy(), copy_if(), copy_n()
STL 알고리즘 중 "변경 순차 알고리즘"에 대해 알아보겠습니다.
"전문가를 위한 C"의 17 항목, "STL 알고리즘 마스터하기"에 해당하는 내용입니다.
변경 순차 알고리즘
원본 항목들을 다른 구간에 복제해 넣거나, 삭제하거나, 변경하는 등의 "변경 순차 알고리즘"은 당연하게도 원본 항목들에 변경을 가합니다.
이러한 알고리즘들은 모두 "원본 범위"에서 항목들을 읽어드리고, 읽어드린 항목들을 통해 "대상 범위"에 추가하거나, 수정합니다.
물론, "원본 범위" == "대상 범위"의 경우도 가능합니다.
* 주의: map, multimap, set, 그리고 multiset 등의 순차 연관 컨테이너들은 변경 순차 알고리즘에서 "대상 범위"에 지정할 수 없습니다. 이들은 모두 "key" + "value" 쌍으로 항목을 구성하고 있고, "key" 값은 const로 변경이 불가능하기 때문입니다.
transform(), 콜백 함수를 통해 교체
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v{ 10, 20, 30, 40, 50 };
cout << "Orginal values in the vector are : ";
for (auto& val : v)
cout << val << " ";
cout << '\n';
// transform( 원본 범위 시작, 원본 범위 끝, 대상 범위 시작, 콜백 함수 )
transform(begin(v), end(v), begin(v), [](int num) ->int { return num + 100; });
cout << "Changed values in the vector are: ";
for (auto& val : v)
cout << val << " ";
}
* 결과 화면
"transform()" 알고리즘은 "원본 범위"의 항목들에 대해 콜백 함수를 호출하고, 그 결과물을 "대상 범위"에 추가합니다.
이때, "원본 범위"의 항목들을 결과 값과 교체하길 원한다면, 원본 범위 == 대상 범위로 설정합니다!
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v{ 1, 2, 3 };
vector<int> v2{ 11, 22, 33 };
cout << " First vector : ";
for (auto& val : v)
cout << val << " ";
cout << '\n';
cout << " Second vector : ";
for (auto& val : v2)
cout << val << " ";
cout << '\n';
// 두 항목을 쌍으로 받는 이항 콜백 함수 버전
transform(begin(v), end(v), begin(v2), begin(v), [](int a, int b) ->int {return a + b; });
cout << " Final First vector : ";
for (auto& val : v)
cout << val << " ";
cout << '\n';
cout << " Final Second vector : ";
for (auto& val : v2)
cout << val << " ";
cout << '\n';
}
* 결과 화면
"transform()" 알고리즘의 두 번째 버전은 두 항목을 인자로 받는 이항 콜백 함수 사용입니다.
" transform( 첫 번째 원본 범위 시작, 첫 번째 원본 범위 끝, 두 번째 원본 범위 시작, 대상 범위 시작, 이항 함수)"의 인터페이스를 갖고 있습니다.
직관적으로 이해하기 힘들지만, 자세히 살펴보면 "두 개의 원본 범위"를 콜백 함수의 인자로 받고 주어진 대상 범위에 추가하는 것으로 이해하면 되겠습니다.
copy(), copy_if(), copy_n(), 원본 범위를 대상 범위로 복사(덮어쓰기)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v1{ 10, 20, 30, 40, 50 }, v2{11, 22};
cout << "V1 : ";
for (auto const& val : v1)
cout << val << " ";
cout << '\n';
cout << "V2 : ";
for (auto const& val : v2)
cout << val << " ";
cout << "\n";
// Step 1: "resize()" 메서드를 통해 v1의 항목들을 v2로 복제하기위한 충분한 공간을 확보합니다.
v2.resize(v1.size());
// Step 2: copy( 원본 범위의 시작, 원본 범위의 마지막, 대상 범위의 시작 )
copy(cbegin(v1), cend(v1), begin(v2));
cout << "Vector1 -> Vector 2 : ";
for (const auto& val : v2)
cout << val << " ";
}
* 결과 화면
"copy()" 알고리즘은 원본 범위의 항목들을 대상 범위에 차례대로 복제합니다.
"copy()" 알고리즘은 값을 복제하여 덮어쓰기 때문에, 새로운 항목을 삽입하는 데에 사용할 수 없습니다.
따라서, 대상 범위에 미리 저장된 항목들은 삭제되고, 복제된 항목들이 새롭게 추가된다고 보면 됩니다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v1{ 10, 20, 30, 40, 50 }, v2{11, 22};
cout << "V1: ";
for (const auto& val : v1)
cout << val << " ";
cout << '\n';
cout << "V2: ";
for (const auto& val : v2)
cout << val << " ";
cout << '\n';
// 1. Step 1: v2에 충분한 공간을 먼저 확보합니다.
v2.resize(v1.size());
// 2. Step 2: Predicate에 합치하는 v1의 항목들을 v2로 복제합니다.
auto endIt = copy_if(cbegin(v1), cend(v1), begin(v2), [](int num) {return num > 30; });
// 3. Step 3: 실제 복제가 실행된 범위보다 오버해서 할당 받은 공간을 삭제합니다.
v2.erase(endIt, end(v2));
cout << "V1 > 30인 항목들을 -> V2 : ";
for (const auto& val : v2)
cout << val << " ";
}
* 결과 화면
"copy_if()"의 경우 추가적으로 프레디 킷 함수를 인자로 받습니다.
원본 범위의 항목들 중 프레디킷 함수와 합치하는 항목들을 대상 범위로 덮어쓰기 합니다.
이때, "copy_if()"의 반환 값은 복제된 항목들 중 마지막 항목의 직후 위치에 접근하는 반복자를 반환합니다.
이 반복자를 통해 오버해서 할당받은 공간을 삭제하는 것이 가능해지겠죠!
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> v1{ 10, 20, 30, 40, 50 }, v2{11, 22};
cout << "V1 : ";
for (const auto& val : v1)
cout << val << " ";
cout << '\n';
cout << "V2 : ";
for (const auto& val : v2)
cout << val << " ";
cout << '\n';
// Step 1. 충분한 공간을 확보하기위해 "resize()"를 호출합니다.
size_t n = 3;
v2.resize(min(v1.size(), n));
// Step 2. "copy_n()"을 통해 원본 범위의 n개 항목을 대상 범위로 복제합니다.
copy_n(cbegin(v1), n, begin(v2));
cout << " V1 -> V2 " << n << "개 항목만 복제합니다 : ";
for (const auto& val : v2)
cout << val << " ";
}
* 결과 화면
"copy_n()" 알고리즘은 주어진 원본 범위의 항목들 중 "n"개 항목들을 대상 범위로 복제합니다!
먼저, 대상 컨테이너의 공간을 "min( v1.size(), n )"만큼 재할당 받습니다.
그리고 "copy_n(원본 범위 첫 번째, 개수, 대상 범위의 첫 번째)"를 통해 "n"개 항목들을 복제합니다.
'언어 > Basic C++' 카테고리의 다른 글
[Basic C++] #52_STL 알고리즘, replace (0) | 2022.07.19 |
---|---|
[Basic C++] #51_STL 이동 알고리즘, move (0) | 2022.07.19 |
[Basic C++] #49_STL 알고리즘, 불변 순차 알고리즘 (0) | 2022.07.13 |
[Basic C++] #48_함수 객체 어댑터, 바인더, not1(), not2(), mem_fn() (0) | 2022.07.09 |
[Basic C++] #47_함수 객체 (0) | 2022.07.08 |