★ SPECIAL
STL アルゴリズム威力ショーケース
「C 時代に 20 行で書いていた処理が、STL なら 1 行」— それは本当。16 の実例を Before / After で並べます。コード行数・バグリスク・意図の伝わりやすさが桁違いに良くなるのを体感してください。
01配列の合計 12→1 行
std::accumulate を使うだけ。for ループの初期化忘れや境界バグから解放。
C12 行
int sum = 0;
for (int i = 0; i < n; ++i) {
sum += a[i];
}
// ・i 型を sz_t にしないと警告
// ・n を size_t に揃えるのも面倒
// ・overflow 検出は手動
STL1 行
auto sum = std::accumulate(v.begin(), v.end(), 0LL);
ポイント: 初期値 0LL を渡せば自動で 64bit で足してくれる。overflow 対策がパラメータ 1 個で済む。
02最小・最大を同時に求める 15→1 行
C15 行
int mn = a[0], mx = a[0];
for (int i = 1; i < n; ++i) {
if (a[i] < mn) mn = a[i];
if (a[i] > mx) mx = a[i];
}
// ・n==0 の時に a[0] で UB
STL1 行
auto [mn, mx] = std::minmax_element(v.begin(), v.end());
空でもend() が返るので安全。構造化束縛 + pair でイテレータ 2 本取り出し。
03偶数だけ取り出す 18→2 行
C18 行
int even[100], cnt = 0;
for (int i = 0; i < n; ++i) {
if (a[i] % 2 == 0) even[cnt++] = a[i];
}
// ・バッファサイズ 100 ハードコード
// ・cnt++ を 100 で割らないと OOB
STL2 行
std::vector<int> even;
std::copy_if(v.begin(), v.end(), std::back_inserter(even),
[](int x){ return x%2==0; });
back_inserter が vector を自動で拡張。バッファサイズの悩みから解放。
04ソート + 重複削除 30→3 行
C30 行
// qsort でソートし、in-place で unique 作業
qsort(a, n, sizeof(int), cmp_int);
int j = 0;
for (int i = 0; i < n; ++i) {
if (i == 0 || a[i] != a[i-1])
a[j++] = a[i];
}
n = j;
// ・cmp_int を自作(20 行以上)
// ・void* キャスト
STL3 行
std::sort(v.begin(), v.end());
v.erase(std::unique(v.begin(), v.end()),
v.end());
これが有名な erase-unique イディオム。コンパイラが整数比較に operator< を inline 展開するので qsort より速いことも。
05各要素を 2 倍 8→1 行
C8 行
int out[100];
for (int i = 0; i < n; ++i) {
out[i] = a[i] * 2;
}
STL1 行
std::transform(v.begin(), v.end(), out.begin(),
[](int x){ return x*2; });
06文字列を大文字化 10→1 行
C10 行
for (int i = 0; s[i]; ++i)
s[i] = toupper(s[i]);
STL1 行
std::transform(s.begin(), s.end(), s.begin(), ::toupper);
07配列内にある値を探す 10→1 行
C10 行
int pos = -1;
for (int i = 0; i < n; ++i) {
if (a[i] == target) { pos = i; break; }
}
STL1 行
auto it = std::find(v.begin(), v.end(), target);
// 見つからなければ it == v.end()
08条件を満たす個数 8→1 行
C8 行
int cnt = 0;
for (int i = 0; i < n; ++i)
if (a[i] > 0) ++cnt;
STL1 行
auto cnt = std::count_if(v.begin(), v.end(),
[](int x){ return x > 0; });
09二分探索 20→1 行
C20 行
int lo = 0, hi = n;
while (lo < hi) {
int mi = (lo + hi) / 2; // overflow 潜在
if (a[mi] < target) lo = mi + 1;
else hi = mi;
}
// ・+hi overflow を考えるなら lo+(hi-lo)/2
STL1 行
bool found = std::binary_search(v.begin(), v.end(), target);
// 位置も欲しいなら lower_bound
オーバーフロー対策が標準ライブラリに内蔵。事前に sort されていることが前提。
102 つの配列の交差 25→3 行
STL3 行
// a, b は sorted
std::vector<int> common;
std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
std::back_inserter(common));
C で書くと二重ループの罠、O(n·m)。STL なら自動的に O(n+m)。
11条件でパーティション分割 18→1 行
STL1 行
auto it = std::partition(v.begin(), v.end(),
[](int x){ return x%2==0; });
// 前半: 偶数、後半: 奇数
12全要素が条件を満たすか 7→1 行
STL1 行
bool all_pos = std::all_of(v.begin(), v.end(),
[](int x){ return x > 0; });
// any_of / none_of もある
13配列の並びを逆順に 7→1 行
STL1 行
std::reverse(v.begin(), v.end());
14シャッフル 15→3 行
STL3 行
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
C の rand() % n でのシャッフルはバイアスがある(Fisher-Yates で自作しないと)。STL なら Fisher-Yates が内蔵。
15順列を全列挙 40→3 行
STL3 行
std::sort(v.begin(), v.end());
do { use(v); }
while (std::next_permutation(v.begin(), v.end()));
順列列挙を自作すると再帰+バックトラックで 30 行以上。STL はこれだけ。
16ファイルから全行を読み込む 25→4 行
STL4 行
std::ifstream f(path);
std::vector<std::string> lines;
for (std::string l; std::getline(f, l); )
lines.push_back(std::move(l));
fgets のバッファサイズ悩みも、EOF 判定ロジックも、手動 malloc/free も不要。