[STL] 원소를 수정하는 알고리즘 (2)



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;
}

image

직관적이므로 설명은 생략한다.

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;
}

image

직관적이므로 설명은 생략한다.

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] << " ";
	}
}

image

직관적이므로 설명은 생략한다.

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] << " ";
	}
}

image

직관적이므로 설명은 생략한다.

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] << " ";
	}
}

image

직관적이므로 설명은 생략한다.

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] << " ";
	}
}

image

결과와 같이 원본 순차열의 원소들은 그대로다.

(참고) 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;
}

image

직관적이므로 설명은 생략한다.

두 순차열에 연산이 다능한 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;
}

image

결과와 같이 원본들의 값은 변하지 않고 두 순차열의 합을 v3에 저장하는걸 알 수 있다. 그리고 STL에서 제공하는 조건자 plus<int>()를 사용할 수 있음도 알 수 있다.

여태까지 원소를 수정하는 알고리즘을 정리하였는데 여기서 가장 주의해야 할 점은 원소를 수정하는 알고리즘은 모두가 덮어쓰기 모드로 동작하기 때문에 목적지 순차열은 원본 순차열 이상의 원소를 가지고 있어야 한다.




© 2022. by KSC

Powered by sora