특정 컨테이너를 1, 2, ... , 10 으로 채우려면 어떻게 해야 할까요?
제일 쉬운 방법은 이전 글(5번)에서 설명한
iota 알고리듬을 사용하는 방법입니다.
vector<int> v1(10);
iota(v1.begin(), v1.end(), 1);
generate를 사용하려면 어떻게 해야 할까요?
다음과 같은 함수 객체를 만들면 됩니다.
3번 글에서 Cin 함수 객체를 만들었던 것과 유사하나,
생성자에 시작 값(start)을 지정하는 파라미터를 추가하였습니다.
class IntSeq {
public:
IntSeq(int start = 0) : current(start) { }
int operator()() { return current++; }
private:
int current;
};
....
generate(v1.begin(), v1.end(), IntSeq(1));
그럼 이번에는 0~99까지의 임의의 난수로 채우려면 어떻게 해야 할까요?
역시 iotaGen과 비슷합니다.
생성자에 범위(range)를 지정하는 파라미터를 사용합니다.
class RandomGenerator {
public:
RandomGenerator(int r) : range(r) { randomize(); } // 난수 생성기를 초기화합니다.
int operator() () { return random(range); } // 파라미터가 없습니다.
private:
int range;
};
// randomize()와 random()은 볼랜드 C에만 있습니다.
// 다른 컴파일러 사용자는 적당히 알아서(?) 구현하세요.
generate(v1.begin(), v1.end(), RandomGenerator(100));
자, 이번에는 화제를 돌려서
random_shuffle 알고리듬을 알아봅시다.
template <class RandomAccessIterator>
void random_shuffle(RandomAccessIterator first, RandomAccessIterator last);
template <class RandomAccessIterator, class RandomNumberGenerator>
void random_shuffle(RandomAccessIterator first, RandomAccessIterator last,
RandomNumberGenerator& rand)
이 알고리듬은 [first, last)까지의 시퀀스를 임의로 뒤섞는 기능을 합니다.
그런데 여기서, 별도의 RandomNumberGenerator를 사용하지 않은 첫번째 알고리듬에는
한가지 문제점이 있습니다.
프로그램을 실행할 때마다 똑같은 결과가 나온다는 거지요.
즉, random_shuffle 자체가 사용하는 난수 생성기는 (예를 들어 randomize()를 써서)
실행할 때마다 난수를 초기화시키는 기능이 없다는 얘기입니다.
결국 난수를 초기화 기능을 사용하려면
별도의 사용자 정의 RandomNumberGenerator를 사용해야 합니다.
그런데, 이 RandomNumberGenerator는 앞에서 generate에 사용한 함수 객체와는
다른 방법으로 정의해야 합니다.
즉, 앞에서 사용된 함수 객체는 객체 생성자에는 파라미터를 사용할 수 있지만,
함수 호출시에는 파라미터가 없습니다. 이러한 함수 객체를 Generator라고 합니다.
그러나 random_shuffle에서 사용하는 함수 객체는 파라미터 1개가 반드시 필요합니다.
이러한 함수 객체를 Unary Function이라고 합니다.
만약 파라미터가 두개가 필요한 경우는 Binary Function이라고 합니다.
여기서 정의할 함수 객체를 RandomFunction이라고 하겠습니다.
이 경우는 생성자에 파라미터가 필요없고, 멤버 변수도 필요없기 때문에
훨씬 간단하게 정의할 수 있습니다.
// Example for random_shuffle()
#include<cstdlib>
#include<iostream>
#pragma hdrstop
#include<vector>
#include<iterator>
#include<algorithm>
#include<numeric>
using namespace std;
struct RandomFunction {
RandomFunction() { randomize(); }
int operator() (int X) { return random(X); }
};
int main() {
vector<int> v(12);
iota(v.begin(), v.end(), 0); // 0 1 2 3 4 5 6 7 8 9 10 11
ostream_iterator<int> out(cout, " ");
copy(v.begin(), v.end(), out);
cout << endl;
random_shuffle(v.begin(), v.end()); // 1 5 11 2 6 4 10 8 7 0 9 3 (빌더 6 STLport의 경우)
copy(v.begin(), v.end(), out);
cout << endl;
random_shuffle(v.begin(), v.end(), RandomFunction()); // 매번 실행 시마다 다르다.
copy(v.begin(), v.end(), out);
cout << endl;
return 0;
}
|