덮어쓰기 모드로 동작하기 때문에 ➡ 목적지 순차열은 원본 이상의 원소를 가지고 있어야 한다.
➡ ✅ 기존 반복자 위치에 직접 써버리는 것이기 때문에 충분한 공간이 있어야 한다는 것!!
| 알고리즘 함수 | 사용 형태 (인자) | 역할 | 반환값 |
|---|---|---|---|
| copy | copy(first, last, out_first) | [first, last) 범위를 out_first부터 복사 | 출력 반복자 (out_first + 거리) |
| fill | fill(first, last, value) | [first, last) 구간을 모두 value로 채움 | void |
| fill_n | fill_n(out_first, count, value) | count개의 값을 out_first부터 value로 채움 | 출력 반복자 (out_first + count) |
| for_each | for_each(first, last, func) | [first, last) 범위의 각 원소에 func(x) 적용 (출력, 수정 가능) | 함수 객체 (복사본) |
| generate | generate(first, last, gen) | [first, last) 구간을 함수 gen()으로 생성 | void |
| generate_n | generate_n(out_first, count, gen) | count개의 값을 gen()으로 생성해 out_first부터 채움 | 출력 반복자 (out_first + count) |
| swap | swap(a, b) | 두 변수 a, b의 값을 교환 | void |
| iter_swap | iter_swap(it1, it2) | 반복자 it1, it2가 가리키는 값을 교환 | void |
| swap_ranges | swap_ranges(first1, last1, first2) | [first1, last1) ↔ first2부터 같은 거리의 값을 교환 | first2 + 거리 |
| transform (단일 입력) | transform(first, last, out_first, unary_op) | unary_op(x) 적용 결과를 out_first부터 저장 | 출력 반복자 (out_first + 거리) |
| transform (이중 입력) | transform(first1, last1, first2, out_first, binary_op) | binary_op(x, y) 결과를 out_first부터 저장 | 출력 반복자 (out_first + 거리) |
| merge | merge(first1, last1, first2, last2, out_first) | 정렬된 두 범위를 병합하여 out_first부터 저장 | 출력 반복자 (out_first + 거리) |
| merge (함수 객체 사용) | merge(first1, last1, first2, last2, out_first, comp) | 사용자 정의 비교 함수로 병합 결과 저장 | 출력 반복자 (out_first + 거리) |
| replace | replace(first, last, old_val, new_val) | [first, last)에서 old_val을 new_val로 직접 교체 | void |
| replace_if | replace_if(first, last, pred, new_val) | 조건(pred)을 만족하는 원소를 new_val로 직접 교체 | void |
| replace_copy | replace_copy(first, last, out_first, old_val, new_val) | 원본은 유지하고 old_val → new_val 변환 후 복사 | 출력 반복자 (out_first + 거리) |
| replace_copy_if | replace_copy_if(first, last, out_first, pred, new_val) | 조건 만족하는 원소만 new_val로 바꾸어 복사 | 출력 반복자 (out_first + 거리) |
1구간 반복자를 2구간의 시작 반복자에 복사한다.
➡ 복사된 마지막 원소를 가리키는 반복자를 반환한다. (제일 뒤)
int main()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
vector<int> v2(3); // 사이즈 3 {0, 0, 0} 상태
vector<int>::iterator iter = copy(v.begin(), v.end(), v2.begin());
cout << "마지막 원소 : " << * (iter - 1) << endl;
for (int i = 0; i < v2.size(); i++)
{
cout << v2[i] << " "; // 복사된 후 v2의 값
}
}
뒤에서 부터 앞으로 값이 복사된다.
➡ 복사된 마지막 원소를 가리키는 반복자를 반환한다. (제일 앞)
int main()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
vector<int> v2(6); // 사이즈 3 {0, 0, 0, 0, 0, 0} 상태
vector<int>::iterator iter = copy_backward(v.begin(), v.end(), v2.end()-1);
cout << "v2의 마지막 원소 : " << *iter << endl;
for (int i = 0; i < v2.size(); i++)
{
cout << v2[i] << " ";
}
}
반환값은 없다. (void)
정의한 반복자 구간 내의 원소를 원하는 값으로 채운다. ➡ 덮어 씌우는 방식
➡ 시작 반복자 위치에서 +n의 위치까지 요소를 채운다. 즉, fill_n(b, b+e, n);
int main()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
fill(v1.begin(), v1.end(), 0); // 구간에 값들을 0으로 채우기
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 0 0 0
}
cout << endl;
// ----------------------------
fill_n(v1.begin(), 2, 55);
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 0 0 0
}
}
참조를 통해 원본의 원소 값이 직접 수정된다.
➡ 아래의 코드를 보면 v1의 각 원소들의 값이 참조를 통해 +5가 적용된다.
void Func(int & r) // 반환값이 없다.
{
r += 5;
}
int main()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
for_each(v1.begin(), v1.end(), Func);
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 15 25 35
}
}
누적된 값을 사용하는 경우, 각 원소들이 total에 누적되고 r을 갱신하고 출력된다.
// 누적된 값을 사용하는 경우
class Calculate
{
int total;
public:
Calculate(int init = 0) : total(init) { }
void operator() (int& r)
{
total += r;
r = total; // r값에 적용되어야 v1원소에 적용된다.
}
};
int main()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
for_each(v1.begin(), v1.end(), Calculate(0));
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 10 30 60
}
}
구간의 모든 원소를 f( ) 함수를 통해 채우는 방법
➡ 아래의 코드는 v1의 모든 원소들을 1씩 증가하면서 채운다.
class Calculate
{
int total;
public:
Calculate(int init = 0) : total(init) { }
int operator() ()
{
return total++;
}
};
int main()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
generate(v1.begin(), v1.end(), Calculate(0));
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 0 1 2
}
// ------------------------------------
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
// [v1.begin() ~ v1.begin()+1) 구간 반복자
generate_n(v1.begin(), 1, Calculate(0));
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 0 20 30
}
}
int main()
{
int a = 5; int b = 1;
swap(a, b);
cout << a << " " << b; // 1 5
// -------------------------------
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
// 반복자끼리 스왑
iter_swap(v1.begin(),v1.begin()+1);
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 20 10 30
}
}
➡ 1구간과 2구간을 병합하여 3구간에 저장한다.
merge()를 사용하기 위해서는 정렬되어있는 순차열만 사용 가능하다. ➡ 기본 오름차순 정렬
int main()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
vector<int> v2;
v2.push_back(60);
v2.push_back(70);
v2.push_back(80);
vector<int> v3 (8); // 사이즈 8
vector<int>::iterator iter = merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for (int i = 0; i < v3.size(); i++)
{
cout << v3[i] << " "; // 10 20 30 60 70 80 [0] 0
}
cout << endl << "목적지 끝 반복자 : " << *iter; // [0]
}
➡ 사용자 정의 함수 객체를 사용한 경우
아래의 코드는 사용자 정의 내림차순을 적용한 코드이다.
template <typename T>
struct Greater // 내림차순 정렬
{
bool operator()(const T& left, const T& right) const
{
return left > right;
}
};
int main()
{
vector<int> v1;
v1.push_back(30);
v1.push_back(20);
v1.push_back(10);
vector<int> v2;
v2.push_back(80);
v2.push_back(70);
v2.push_back(60);
vector<int> v3 (8); // 사이즈 8
vector<int>::iterator iter = merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin(), Greater<int>());
for (int i = 0; i < v3.size(); i++)
{
cout << v3[i] << " "; // 80 70 60 30 20 10 0 0
}
cout << endl << "목적지 끝 반복자 : " << *iter; // [0]
}
bool Calculate(int n)
{
return 20 <= n; // 20보다 크다면 교체
}
int main()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
replace(v1.begin(), v1.end(), 10, 5); // 10인 원소를 5로 교체
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 5 20 30
}
// -----------------------------------
replace_if(v1.begin(), v1.end(), Calculate, 1); // 20보다 큰 원소를 1로 교체
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 5 1 1
}
}
replace + copy == 즉, 값을 교체하고 복사한 값을 저장하기
➡ replace_copy_if() 는 조건에 만족하면 원소를 교체하고 복사한 값을 저장
bool Calculate(int n)
{
return 20 <= n; // 20보다 크다면 교체
}
int main()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
vector<int> v2(6); // 사이즈 6
// 10인 원소를 5로 교체 후 v2에 저장
replace_copy(v1.begin(), v1.end(),v2.begin(), 10, 5);
for (int i = 0; i < v2.size(); i++)
{
cout << v2[i] << " "; // 5 20 30 0 0 0
}
// ------------------------------
vector<int> v3(6); // 사이즈 6
// 20이상인 원소를 1로 교체 후 v3에 저장
replace_copy_if(v1.begin(), v1.end(), v3.begin(), Calculate, 1);
for (int i = 0; i < v3.size(); i++)
{
cout << v3[i] << " "; // 10 1 1 0 0 0
}
}
두 순차열의 반복자 구간의 범위를 모두 바꾸는 방법
➡ 서로의 순차열의 원소 값이 바뀐다.
int main()
{
vector<int> v1;
v1.push_back(10); // 변경
v1.push_back(20);
v1.push_back(30);
vector<int> v2;
v2.push_back(50); // 변경
v2.push_back(60);
v2.push_back(70);
swap_ranges(v1.begin(), v1.begin() + 1, v2.begin());
for (int i = 0; i < v2.size(); i++)
{
cout << v2[i] << " "; // 10 60 70
}
cout << endl;
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 50 20 30
}
}
반환타입을 가지고, for_each()와는 다르게 값이 복사되어 들어가기 때문에 다른 컨테이너 값을 저장할 수 있다. ➡ 이 경우엔, 원본 값은 변경되지 않는다.
아래의 경우는 v1 순차열에 값이 복사되어 Func()을 거치고 반환된 값들이 다시 v1 순차열로 저장되기 때문에 원본의 값이 변경된다.
// 반환 타입을 가진다.
int Func(int n)
{
return n + 5;
}
int main()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
vector<int>::iterator iter = transform(v1.begin(), v1.end(), v1.begin(), Func);
cout << "목적지의 끝 반복자 : " << *(iter - 1) << endl;
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " "; // 15 25 35
}
}
아래의 경우는 v1의 순차열과 v2의 순차열을 서로 더한 뒤 반환된 값을 v3에 저장한다.
➡ 원본의 값은 변경되지 않는다.
// 반환 타입을 가진다.
int Plus(int left, int right)
{
return left + right;
}
int main()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
vector<int> v2;
v2.push_back(10);
v2.push_back(20);
v2.push_back(30);
vector<int> v3 (10); // 사이즈 10
vector<int>::iterator iter = transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), Plus);
cout << "목적지의 끝 반복자 : " << *(iter - 1) << endl;
for (int i = 0; i < v3.size(); i++)
{
cout << v3[i] << " "; // 15 25 35
}
}
for_each()
주로 출력, 누적에 사용된다.
참조를 통해 실제 원본의 값에 적용될 수 있고, 출력할 때 적용된 값이 나온다.
함수의 반환값이 없다.
➡ ⭐출력 매개변수를 사용하기 때문에 & 사용
transform
반환값이 있고, 반환 값을 사용하여 사용자 동작(함수)을 원소에 적용한다.
➡ ⭐값을 복사하고, Func()을 지나 값을 반환한다.
➡ 복사된 값을 사용하기 때문에 만약 원본값에서 다른 곳에 추가 할 경우 원본 값은 변화가 없다.
➡ 만약 원본값에 그대로 적용 할 경우엔 원본 값에 변화가 적용된다.