アットウィキロゴ

アルゴリズムを使ってみる


初めに簡単なアルゴリズムのサンプルを示します。
アルゴリズムを使用する場合は記述されているヘッダをinlucdeする必要があります。
ここでは

#include <algorithm>

を記述してください。
また、STLは全てstdの名前空間に記述されているので事前に

using namespace std;


を記述するといいでしょう。
使用するアルゴリズムはfillです。
このfillアルゴリズムは指定した範囲に指定した値を充填します。

※コンテナ・イテレータの解説までコンテナは配列・イテレータはポインタで代用しています。
しばらくはコンテナは配列・イテレータはポインタと覚えていても間違いではないでしょう。





例1
#include <algorithm>

using namespace std;

int main(int argc, char * argv[])
{
   int v[10 ];

   fill(v, v+10, 100 );

   for (int i = 0; i < 10; i++)
       printf("%d,", v[i]);

   return 0 ;
}





実行結果
100,100,100,100,100,100,100,100,100,100,




以下の記述がアルゴリズムを使用している箇所です。

fill(v, v+10, 100);

アルゴリズムfillは第一引数に充填を開始するイテレータ(配列の先頭)を、第二引数に充填を終了するイテレータ(配列末尾の1つ後ろ)を、第三引数に充填する値を渡します。
結果は実行結果をご覧ください。
指定された要素が全て充填されていることがわかります。
このようにSTLのアルゴリズムはイテレータ(ポインタ)経由でデータに対し、ある処理(アルゴリズム)を適用します。

※STLでは終了を示すイテレータは要素の最後の一つ後ろを指すことが慣例となっています。




コンテナを使ってみる


次にコンテナを使用してみましょう。
以下に簡単なコンテナのサンプルを示します。
コンテナを使用する場合は記述されているヘッダをinlucdeする必要があります。
ここでは

#include <vector>

を記述してください。
もちろん

using namespace std; 

を忘れないでください。
使用するコンテナはvectorです。
これは動的な伸縮可能な配列です。




例2

#include <vector>

using namespace std;

int main(int argc, char* argv[])
{
   vector<int> v;

   v.push_back(1);
   v.push_back(2);
   v.push_back(3);
   v.push_back(4);
   v.push_back(5);

   for (int i = 0; i < 5; i++)
       printf("%d,",v[i]); 

   return 0;
}



実行結果
1,2,3,4,5,



vector<int> v;

がint型のvectorをデフォルトコンストラクタで生成しています。
この時、配列サイズはまだ0です。

v.push_back(1);

v.push_back(5);

ではvectorのメンバ関数push_backを使用し要素を終端に追加しています。
要素が追加されると動的に配列サイズが拡張されます。
(この場合、vはサイズ0からサイズ5へ拡張した)

for (int i = 0; i < 5; i++)
   printf("%d,",v[i]); 

で全要素を出力しています。

このようにSTLのコンテナを使用すれば動的に配列要素数を変更できます。


イテレータを使ってみる


イテレータとはコンテナが提供するオブジェクトへのアクセス機能を持ったオブジェクトです。
これまでポインタで代用してきましたがポインタもイテレータと同じ機能を有していますので、
ポインタもイテレータと思って間違いではありません。
しかし、このままですとイテレータとはポインタのことか?となりかねません。
ここでは実際にイテレータを使用してみます。

vector<int> v(10);
vector<int>::iterator ite = v.begin();

上記がイテレータの簡単な作成例です。

vector<int> v(10);

で、配列要素数10のvectorのvを作成します。

vector<int>::iterator ite = v.begin();

で、iteに配列要素数10のvectorの先頭を指し示すイテレータを取得しています。
ちなみに

vector<int>::iterator ite2 = v.end();

で、ite2にvの終端を指し示す(終端データの次を指し示す)イテレータを取得しています。
以下にイテレータを使用し配列を充填するサンプルを示します。
ただし、アルゴリズムfillは使用していません。
イテレータ経由でデータを充填しています。




例3

#include <vector>

using namespace std;

int main(int argc, char* argv[])
{
   vector<int> v(10);

   vector<int>::iterator ite1 = v.begin();

   for (;ite1 != v.end(); ite1++)
       *ite1 = 100;

   vector<int >::iterator ite2 = v.begin(); 
   for (; ite2 != v.end(); ite2++)
       printf("%d,",*ite2); 

   return 0;
}




実行結果
100,100,100,100,100,100,100,100,100,100,



vector<int> v(10);

ここでint型vector配列を要素数10で構築しています。

vector<int>::iterator ite1 = v.begin();


for (;ite1 != v.end(); ite1++)
   *ite1 = 100;

ここではv.begin()でvectorコンテナの先頭を示すイテレータを取得し、

for (;ite1 != v.end(); ite1++)

で、コンテナの終端までループします。
v.end()はコンテナの終端の要素の一つ次を指し示します(STLの慣例です)のでこれで問題ありません。

*ite1 = 100;

で、イテレータを介し100を代入しています。
結果として全要素を100で充填していることになります。

これが問題なく動作するのはコンテナが提供するイテレータのoperator++()・oerator*()が
実装されているためです。
そのためポインタをイテレータの代わりに使用しても動作していたのです。
(厳密に言えばポインタとイテレータは違うのですがここでは同じと理解してかまいません)




例4

#include <vector>
#include <algorithm>

using namespace std;

int main(int argc, char* argv[])
{
   vector<int> v(10);

   fill(v.begin(),v.end(),100);

   vector<int>::iterator ite2 = v.begin() 
   for (; ite2 ! = v.end(); ite2++)
       printf("%d,",*ite2); 

   return 0;
}



実行結果
100,100,100,100,100,100,100,100,100,100,



例4は充填にアルゴリズムを使用した例です。
ここまでくれば例1のポインタ版・例4のイテレータ版ともに動作する理由がわかったのではないでしょうか。
最終更新:2006年11月28日 00:50