[STL] 원소를 수정하는 알고리즘 (2)
in STL
replace()
replace()는 순차열의 특정원소를 다른 값으로 수정하고 싶을 때 사용한다. replace(b,e,x,x2)는 구간 [b,e)의 순차열에서 x인 원소를 x2로 바꾼다. 예시를 보자.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(30);
v1.push_back(30);
v1.push_back(50);
// v1의 모습 10 20 30 40 30 30 50
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
replace(v1.begin(), v1.end(), 30, 0);
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
}
직관적이므로 설명은 생략한다.
replace_if(b,e,f,x2)
사용자가 직접 정의한 조건에 맞는 원소를 수정하고 싶을 때 사용한다. 예시를 보자.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool Pred(int n) {
return 30 <= n && n <= 50; //30에서 50사이인 원소
}
void main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
v1.push_back(60);
v1.push_back(70);
v1.push_back(80);
// v1의 모습 10 20 30 40 50 60 70 80
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
replace_if(v1.begin(), v1.end(), Pred, 0);
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
}
직관적이므로 설명은 생략한다.
replace_copy()
원소를 수정하고 목적지 순차열에 복사하고 싶을 때 사용한다. 예시를 보자.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
v1.push_back(30);
v1.push_back(30);
v1.push_back(80);
// v1의 모습 10 20 30 40 50 30 30 80
vector<int> v2(8);
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
cout << endl;
vector<int>::iterator iter;
// 구간 [v1.begin(),v1.end())의 원소중 30을 0으로 바꾸어 구간 [v2.begin(),iter) 순차열에 저장
iter=replace_copy(v1.begin(), v1.end(), v2.begin(),30, 0);
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
}
직관적이므로 설명은 생략한다.
replace_copy_if()
사용자가 정의한 조건에 맞는 원소를 특정 값으로 바꾸어 목적지 순차열에 복사하고 싶을 때 사용한다. 예시를 보자
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool Pred(int n) {
return n <= 30; //30이하인 원소
}
void main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
v1.push_back(30);
v1.push_back(30);
v1.push_back(80);
// v1의 모습 10 20 30 40 50 30 30 80
vector<int> v2(8);
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
cout << endl;
vector<int>::iterator iter;
// 구간 [v1.begin(),v1.end())의 원소중 30이하인 원소를 0으로 바꾸어 구간 [v2.begin(),iter) 순차열에 저장
iter=replace_copy_if(v1.begin(), v1.end(), v2.begin(),Pred, 0);
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
}
직관적이므로 설명은 생략한다.
swap_ranges()
순차열과 순차열의 모든 원소를 바꾸고 싶을 때 사용한다. swap_ranges(b,e,b2)는 구간 [b,e)의 순차열과 구간 [b2,b2+(e-b))의 모든 원소를 교환한다. 예시를 보자.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
// v1의 모습 10 20 30 40 50
vector<int> v2;
v2.push_back(11);
v2.push_back(22);
v2.push_back(33);
v2.push_back(44);
v2.push_back(55);
// v2의 모습 11 22 33 44 55
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
cout << endl;
swap_ranges(v1.begin(), v1.end(), v2.begin());
cout << endl;
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
}
직관적이므로 설명은 생략한다.
transform()
순차열의 모든 원소에 사용자의 정책(동작)을 반영(적용)하려면 일반적으로 for_each()나 tranform()을 사용한다. transform()이 for_each()랑 다른점은 원본 순차열의 변화 없이 목적지 순차열로 저장하는 점이다.(물론 덮어쓰기 모드로 동작) 예를들어 transform(b,e,t,f)는 구간 [b,e)의 반복자가 p라면 f(*p)를 호출하여 반환값을 순차열 [t,t+(e-b))에 저장한다. 여기서 f는 단항 함수류 이다. 예시를 보자.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int Pred(int n) {
return n + 5;
}
void main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
// v1의 모습 10 20 30 40 50
vector<int> v2(5);
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
cout << endl;
transform(v1.begin(), v1.end(), v2.begin(), Pred);
cout << endl;
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
}
결과와 같이 원본 순차열의 원소들은 그대로다.
(참고) transform()알고리즘은 목적지 순차열의 끝 반복자를 반환한다. 예시를 보자.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int Pred(int n) {
return n + 5;
}
void main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
// v1의 모습 10 20 30 40 50
vector<int> v2(10);
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
cout << endl;
vector<int>::iterator iter_end;
iter_end=transform(v1.begin(), v1.end(), v2.begin(), Pred);
cout << endl;
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
cout << endl;
cout << endl;
cout << "[v2.begin(),iter_end) 순차열 : " << *v2.begin() << "..." << *(iter_end-1);
cout << endl;
}
직관적이므로 설명은 생략한다.
두 순차열에 연산이 다능한 transform()
사용자 연산(함수류 적용)을 두 순차열의 원소에 적용하고자 한다면 transform(b,e,b2,t,f)알고리즘을 사용한다.
이는 구간 [b,e)의 순차열과 구간 [b2,b2+(e-b))의 순차열의 반복자를 각각 p,q라고 하면 f(*p,*q)의 반환값을 구간 [t,t+(e-b))에 저장한다. 예시를 보자.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int Plus(int left,int right) {
return left + right;
}
void main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
// v1의 모습 10 20 30 40 50
vector<int> v2;
v2.push_back(1);
v2.push_back(2);
v2.push_back(3);
v2.push_back(4);
v2.push_back(5);
// v2의 모습 1 2 3 4 5
vector<int> v3(5);
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
cout << endl;
cout << "v3 : ";
for (vector<int>::size_type i = 0; i < v3.size(); i++) {
cout << v3[i] << " ";
}
cout << endl;
vector<int>::iterator iter_end;
// iter_end=transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), plus<int>());
iter_end=transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), Plus);
cout << endl;
cout << "v1 : ";
for (vector<int>::size_type i = 0; i < v1.size(); i++) {
cout << v1[i] << " ";
}
cout << endl;
cout << "v2 : ";
for (vector<int>::size_type i = 0; i < v2.size(); i++) {
cout << v2[i] << " ";
}
cout << endl;
cout << "v3 : ";
for (vector<int>::size_type i = 0; i < v3.size(); i++) {
cout << v3[i] << " ";
}
cout << endl;
cout << endl;
cout << "[v3.begin(),iter_end) 순차열 : " << *v3.begin() << "..." << *(iter_end-1);
cout << endl;
}
결과와 같이 원본들의 값은 변하지 않고 두 순차열의 합을 v3에 저장하는걸 알 수 있다. 그리고 STL에서 제공하는 조건자 plus<int>()를 사용할 수 있음도 알 수 있다.
여태까지 원소를 수정하는 알고리즘을 정리하였는데 여기서 가장 주의해야 할 점은 원소를 수정하는 알고리즘은 모두가 덮어쓰기 모드로 동작하기 때문에 목적지 순차열은 원본 순차열 이상의 원소를 가지고 있어야 한다.