C++の標準ライブラリにはvector
という配列の便利なバージョンみたいなのがあります。
いきなり例を示していきます。以下では全てiostream
とvector
をincludeした上で試してみてください。
#include <iostream>
#include <vector>
vectorを作ってfor文で回してみる
std::vector<int> v = {2, 4, 6, 8, 10};
for (int i = 0; i < 5; ++i) std::cout << v[i] << "\n";
(ちなみにstd::vector<int> v;
と宣言すれば要素数0のvectorができます。)
at
でも参照できる
for (int i = 0; i < 5; ++i) std::cout << v.at(i) << "\n";
at
を使うと存在しない要素(i=8番目とか)を参照しようとするとちゃんとエラーメッセージを出してくれます。そのチェックのために少し動作が遅くなるけど。
vectorの末尾に値を加える
v.push_back(12);
for (int i = 0; i < 6; ++i) std::cout << v.at(i) << "\n";
要素数を知る
std::cout << v.size() << "\n";
1から100000までの自然数の中から7の倍数だけをvectorに詰めよう。
std::vector<int> v;
for (int i = 1; i <= 100000; ++i) {
if (i % 7 == 0) v.push_back(i);
}
実はこれだとpush_back
の度にいちいちメモリを確保する動作が内部的に入って無駄に時間がかかります。先に必要な要素数に対応するメモリをreserve
で予約しておこう。これで速くなります。
std::vector<int> v;
v.reserve(20000);
for (int i = 1; i <= 100000; ++i) {
if (i % 7 == 0) v.push_back(i);
}
ここでpush_back
される要素の数は予約した20000より少ないですが大丈夫です。例えば10000要素分だけreserve
するとかでも大丈夫です。ざっくりとでOK。
このvectorの中から1000の倍数だけ出力してみましょう。
int length = v.size();
for (int i = 0; i < length; ++i) {
if (v[i] % 1000 == 0) std::cout << v[i] << "\n";
}
for文の条件式で要素数分繰り返すような工夫をしているのは1つのポイント。
あと些細なことですがif文の条件式のところはif (!(v[i] % 1000))
と書き換えても同じ結果になりますね。
(ちなみにさっきから改行で"\n"
を使っていますが、これはstd::endl
よりもちょっと速いです。++i
と前置インクリメントにしているのも一応速さを意識していますが、これは後置でもあまり変わらないかも)
length
を定義せずにfor文のところで
for (int i = 0; i < v.size(); ++i) {...}
としたい人がいるかもしれませんが、for文の繰り返しの数だけv
のサイズを計算させることになってしまい処理が遅くなるのでやめておきましょう。
上記でfor文の条件式について色々書きましたが、vectorの要素を最初から最後まで見たい時は範囲ベースfor文を使ってみましょう。
for (auto&& x : v) {
if (!(x % 1000)) std::cout << x << "\n";
}
こうするとlength
なんて定義しなくて良いしfor文の条件式についても悩む必要はなくなります。さらに、処理がとても速くなります。
ループの途中で例えば1000の倍数の時だけ要素の値を5に更新するとかもできます。
for (auto&& x : v) {
if (!(x % 1000)) x = 5;
}
一方、このような値の書き換えをせずに先程のcoutの時みたいに単に要素を参照するだけならば、const修飾子を使うとさらに速く処理できるらしいです。
for (const auto& x : v) {
if (not (x % 1000)) std::cout << x << "\n";
}
!
をnot
に書き換えてみました。全く同じ動作をします。
vectorを空っぽにして最初の状態に戻すにはこうしましょう。
v.clear();
v.shrink_to_fit();