反復子はコンテナを参照、操作するためのもので、
ある決められたインターフェースを備えているものは
何でも反復子となれます。
反復子は入力(出力)反復子、前方反復子、両方向反復子、ランダムアクセス反復子が
あります。また、後ろのものは前のものとしても使えます。
(前方反復子は、入力反復子であり、ランダムアクセス反復子は他の全ての反復子と
して使えます。)
アルゴリズムは、コンテナに対して様々な処理を行う関数の集まりです。
例えば、
fill 初期値でうめる copy コピー generate 生成 find 条件に合う値を探す for_each 全ての要素に対し操作を行うなどがあります。(参照:役に立つ汎用アルゴリズム)
関数オブジェクトは関数のように振る舞うオブジェクトです。()演算子メンバ関数を 持っていれば関数オブジェクトになれます。
#include <vector> #include <list> #include <algorithm> using namespace std;using ... はSTLを使うために必要なものです。とりあえずおまじないだと思って覚えてください。
まず、ベクタを使って見ましょう。配列と同じように使えます。 (VC++4.2では、さらにおまじないが必要になりますが、今回は説明を省略します。)
vector<int> vec(10); for (int i=0;i<10;++i) vec[i] = i;最初の宣言で10個のintを使うことを宣言しています。 (注意:MFCのコレクションクラスと違い、添え字の範囲チェックや自動拡張などは サポートされていません。間違って使用した場合、配列と同じく何が起きるか分かりません。)
リストも殆ど使い方は同じです。
list<int> lst; for (int i=0;i<10;++i) lst.push_back(i);
vector<int> vec(10); vector<int>::iteartor it; for (it=vec.begin();it!=vec.end();++it) *it = i;(注意:時として、(*it).func()のような書き方が出てきますが、 it->func()に直さないで下さい。itが反復子の場合、後者はコンパイルエラーに なることがあります。(ならないこともあります。)なぜなら反復子はポインタと同じように 振る舞っても、ポインタではないからです。)
次に、リストについてもやってみましょう。ベクタと同じように書くことができます。
重要:
2つの反復子を使ってシーケンスを表します。その場合、最初の反復子から次の反復子の
直前までが対象となります。
今回の演習では、以下のアルゴリズムを使うのでヘルプで調べて使えるようにして下さい。 この他にもいろいろあります。
copy(vec.begin(),vec.end(),ostream_iterator<int,char,char_traits<char> >(cout));3番目の引数は、出力ストリーム反復子と呼ばれるものです。呪文だと思って 覚えて下さい。うまくいけば、「0123456789」と出力されます。
next_permutation(vec.begin(),vec.end());順番に順列が生成されます。vec のサイズが3であれば、「123」、「132」、「213」、 「231」、「312」、「321」となります。「321」の次は、また「123」に戻りますが、 そのときだけfalse を返します。
ちなみにvec の代わりにlst でも、あるいは次のような配列でもOKです。
int ary[10]; next_permutation(ary,ary+10);シーケンスは途中でもOKです。
next_permutation(ary+2,ary+5);
アルゴリズムで使える反復子は、プロトタイプ宣言の変数名を見ると、ある程度推測できます。
template <class T> class FuncObj { public: FuncObj(T t) : val(t) {} T operator()(T t){return val + t;} private: T val; };これが、関数オブジェクトのクラス定義です。(テンプレートクラスである必要はありません。) 次のように使えます。
FuncObj<int> fo(3); cout << fo(4); // 7と出力される()演算子を使うと関数のように見えるので関数オブジェクトといいます。 ちなみに、上の例とよく似たものでplus という関数オブジェクトがSTLにあります。
よくある例を1つ。
class Gen { int i; public: Gen(){i = 0;} int operator()(){return ++i;} }; vector<int> v(10); generate(v.begin(),v.end(),Gen());こうすると、v が1から10で初期化されます。
全ての配置を求めて下さい。 下の答えは16837425という出力で構いません。
○ | . | . | . | . | . | . | . |
. | . | . | . | . | . | ○ | . |
. | . | . | ○ | . | . | . | . |
. | . | . | . | . | ○ | . | . |
. | . | . | . | . | . | . | ○ |
. | ○ | . | . | . | . | . | . |
. | . | . | . | ○ | . | . | . |
. | . | ○ | . | . | . | . | . |
1 | 6 | 8 | 3 | 7 | 4 | 2 | 5 |
2 | 7 | 6 |
9 | 5 | 1 |
4 | 3 | 8 |