TopC++ 入門 › 応用 › ★ STL ショーケース
★ SPECIAL

STL アルゴリズム威力ショーケース

「C 時代に 20 行で書いていた処理が、STL なら 1 行」— それは本当。16 の実例を Before / After で並べます。コード行数・バグリスク・意図の伝わりやすさが桁違いに良くなるのを体感してください。

16
実例
−87%
平均コード行数
0
自作ループのバグ

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 も不要。