STLのアルゴリズム
[第]34[課では]STLコンテナについて学び、[データを格納するために何を使うか]を[理解しました]。
[ただ]コンテナ[だけでは不十分]――[さらに][データの処理]も必要です:[検索]、[並べ替え]、[集計]、[変換]……
[自分で書く場合]、[数十行は書かなければならないかもしれない]が、STLアルゴリズムを使えば、[たった1行で済む]。
1. STLアルゴリズム[概要]
(1) 1.1 STLアルゴリズムとは?
STLアルゴリズムとは、C++標準ライブラリが提供する一連の[汎用]関数テンプレートであり、[コンテナ内のデータ]を操作するために用いられる。
[なぜ]STLアルゴリズムを使うのか?
| [自作] | STLアルゴリズム |
|---|---|
| [記入]ループ | [一行]コード |
| [ミスが起きやすい] | [厳格なテストを経た] |
| パフォーマンス[必ずしも高いとは限らない] | [高度な]最適化 |
| コード[長] | コード[簡潔] |
[生活]クラス[比]:
- [自分で洗う]アルゴリズム = [手洗い]([手間と時間がかかる])
- STLアルゴリズム = [洗濯機]([ワンクリックで完了])
(2) 1.2 アルゴリズムヘッダーファイル
[大多数]STLアルゴリズムは、algorithmヘッダーファイル内の[数]valuealgorithm[に] numeric [含まれている]。
▶ サンプル 2: STLアルゴリズム[応用] (難易度 ⭐)
#include algorithm // ...
#include numeric // (accumulate)
(3) 1.3 アルゴリズム[分]クラス
STLアルゴリズム[機能別に分類された]クラス:
| カテゴリ | [代表的な]アルゴリズム | [説明] |
|---|---|---|
| [変更なし]アルゴリズム | find、count、for_each |
[変更なし]コンテナ[内容] |
| [編集]アルゴリズム | copy、transform、replace |
[編集]コンテナ[内容] |
| [ソート]アルゴリズム | sort、stable_sort、partial_sort |
[ソート関連] |
| [二分探索] | binary_search、lower_bound |
[ソート済みの区間での検索] |
| [マージ]アルゴリズム | merge、inplace_merge |
[ソート済み区間のマージ] |
| [数]valuealgorithm | accumulate、inner_product |
[数]value[計算] |
| [集合]アルゴリズム | set_union、set_intersection |
[集合演算] |
2. [変更なし]アルゴリズム
(1) 2.1 検索——[要素の検索]
[機能]: [container]内で指定された要素を検索し、[iterator]を返す。
[原型]:
InputIt find(InputIt first, InputIt last, const T& value);
例:[成績を検索] (難易度 ⭐)
#include iostream
#include vector
#include algorithm
int main() {
std::vectorint scores = {85, 92, 78, 90, 88};
// 90
auto it = std::find(scores.begin(), scores.end(), 90);
if (it != scores.end()) {
// ()
int index = std::distance(scores.begin(), it);
std::cout << "90,:" << index << std::endl;
} else {
std::cout << "90" << std::endl;
}
return 0;
}
[実行結果]:
90,:3
💡 ヒント:
- [見つからない場合は返す]
last([通常は]end()) - [時間計算量]:O(n)
(2) 2.2 カウント——[計数]
[機能]: [指定された]value[に等しい要素の数を]container[内で]集計します。
例:[満点者の人数を統計する] (難易度 ⭐)
#include iostream
#include vector
#include algorithm
int main() {
std::vectorint scores = {100, 85, 100, 92, 78, 100};
// points(100points)
int perfect = std::count(scores.begin(), scores.end(), 100);
std::cout << "points:" << perfect << std::endl; // output:3
return 0;
}
(3) 2.3 for_each——[反復処理]
[機能]: [container]内の各要素に対して指定された操作を実行する。
例:[すべての成績を印刷] (難易度 ⭐)
#include iostream
#include vector
#include algorithm
int main() {
std::vectorint scores = {85, 92, 78, 90, 88};
// lambda
std::for_each(scores.begin(), scores.end(), (int s) {
std::cout << s << " ";
});
std::cout << std::endl;
return 0;
}
[実行結果]:
85 92 78 90 88
💡 ヒント:
for_each[手書きより]ループ[がより簡潔]- [式] lambda [非常に強力な式]
3. [修正]アルゴリズム
(1) 3.1 コピー——[コピー]
[機能]: [ある範囲の要素を別の範囲にコピーする]。
例:array[コピー] (難易度 ⭐)
#include iostream
#include vector
#include algorithm
int main() {
std::vectorint src = {1, 2, 3, 4, 5};
std::vectorint dst(5); //,5
// ...
std::copy(src.begin(), src.end(), dst.begin());
// ...
for (int x : dst) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
(2) 3.2 変換——[変換]
[機能]: [ある範囲の要素を変換し、別の範囲にコピーする]。
例:[成績の加重] (難易度 ⭐⭐)
#include iostream
#include vector
#include algorithm
int main() {
std::vectorint scores = {85, 92, 78, 90, 88};
std::vectorint adjusted(scores.size()); // ...
// 70%,30%
std::transform(scores.begin(), scores.end(), adjusted.begin(),
(int s) { return s * 0.7 + 90 * 0.3; });
std::cout << ":";
for (int x : adjusted) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
[実行結果]:
91.9 81.6 90 88.6
(3) 3.3 置換——[置換]
[機能]: [container]内の[特定の]value[に等しい要素を、別の]value[に置き換える]。
例:[追試験の成績処理] (難易度 ⭐)
#include iostream
#include vector
#include algorithm
int main() {
std::vectorint scores = {85, 92, 78, 90, 88};
// (<60)60()
std::replace_if(scores.begin(), scores.end(),
(int s) { return s < 60; },
60);
std::cout << ":";
for (int x : scores) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
4. [ソート]アルゴリズム
(1) 4.1 ソート——[ソート]
[機能]: [container]の範囲をソート([デフォルトは昇順])。
例:[成績順] (難易度 ⭐)
#include iostream
#include vector
#include algorithm
int main() {
std::vectorint scores = {85, 92, 78, 90, 88};
// ...
std::sort(scores.begin(), scores.end());
std::cout << ":";
for (int x : scores) {
std::cout << x << " ";
}
std::cout << std::endl;
// ...
std::sort(scores.begin(), scores.end(), std::greaterint());
std::cout << ":";
for (int x : scores) {
std::cout << x << " ";
}
std::cout << std::endl;
return 0;
}
[実行結果]:
85 88 90 92:92 90 88 85 78
(2) 4.2 [カスタム並べ替えルール]
例:[成績の高い順に学生を並べ替える] (難易度 ⭐⭐)
#include iostream
#include vector
#include algorithm
#include string
struct Student {
std::string name;
int score;
};
int main() {
std::vectorStudent students = {
{"...", 85},
{"...", 92},
{"...", 78}
};
// ...
std::sort(students.begin(), students.end(),
(const Student& a, const Student& b) {
return a.score > b.score;
});
std::cout << ":" << std::endl;
for (const auto& s : students) {
std::cout << s.name << ":" << s.score << std::endl;
}
return 0;
}
[実行結果]:
5. [数]valuealgorithm
(1) 5.1 累積——[累加]
[機能]: [指定範囲内の要素の累積和を計算する]。
例:[合計点を計算する] (難易度 ⭐)
#include iostream
#include vector
#include numeric
int main() {
std::vectorint scores = {85, 92, 78, 90, 88};
// points
int total = std::accumulate(scores.begin(), scores.end(), 0);
std::cout << "points:" << total << std::endl; // output:433
std::cout << "points:" << total / 5.0 << std::endl; // output:86.6
return 0;
}
(2) 5.2 [内積]
例:[ベクトルの内積] (難易度 ⭐⭐)
#include iostream
#include vector
#include numeric
int main() {
std::vectorint v1 = {1, 2, 3};
std::vectorint v2 = {4, 5, 6};
//:1*4 + 2*5 + 3*6 = 32
int dot_product = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0);
std::cout << ":" << dot_product << std::endl; // output:32
return 0;
}
6. [総合]例
▶ サンプル 1: [成績分析システム] (難易度 ⭐⭐⭐)
#include iostream
#include vector
#include algorithm
#include numeric
#include string
int main() {
std::vectorint scores = {85, 92, 78, 90, 88, 76, 95, 83, 89, 91};
// 1.
int count = scores.size();
std::cout << ":" << count << std::endl;
// 2. and
int total = std::accumulate(scores.begin(), scores.end(), 0);
double average = static_castdouble(total) / count;
std::cout << "points:" << total << ",points:" << average << std::endl;
// 3. searchingand
int max_score = *std::max_element(scores.begin(), scores.end());
int min_score = *std::min_element(scores.begin(), scores.end());
std::cout << "points:" << max_score << ",points:" << min_score << std::endl;
// 4.
int passed = std::count_if(scores.begin(), scores.end(),
(int s) { return s >= 60; });
std::cout << ":" << passed << std::endl;
// 5. sortingandoutput3
std::vectorint top3 = scores;
std::sort(top3.begin(), top3.end(), std::greaterint());
std::cout << "3:";
for (int i = 0; i < 3; i++) {
std::cout << top3[i] << " ";
}
std::cout << std::endl;
return 0;
}
[実行結果]:
3:95 92 91
7. アルゴリズム[活用のコツ]
(1) 7.1 イテレータ[補助]関数
| 関数 | [機能] |
|---|---|
std::distance(first, last) |
[2つの]イテレータ[間の距離を計算する] |
std::advance(it, n) |
[イテレータを]n[ステップ][前進] |
std::next(it) |
[戻る・次へ]iterator |
std::prev(it) |
[前のページに戻る]iterator |
(2) 7.2 ラムダ[式の上級編]
Lambda[式は]STLアルゴリズム[の相棒]です:
// ...
[capture](parameters) -> return_type { body }
//:
std::sort(students.begin(), students.end(),
(const Student& a, const Student& b) {
if (a.score != b.score)
return a.score > b.score; // ...
return a.name < b.name; // ...
});
❓ よくある質問
vector、deque):[効率が高い] - [連想]コンテナ(set、map):[独自の]メンバ関数があり、[メンバ関数を使う方が][速い]Q:ラムダ式とは何ですか? A:ラムダ式とは、C++11で導入された匿名関数であり、関数が必要な場所で直接定義することができます。
[基本構文]:
[capture](params) -> return_type { body }
例:
auto add = (int a, int b) { return a + b; };
std::cout << add(3, 5) << std::endl; // output:8
back_inserterを使用する 3. イテレータ型[不一致] → [コンテナ型]を確認する📖 まとめ
| [知識ポイント] | [要点] |
|---|---|
| STLアルゴリズム | [汎用]関数テンプレート,[操作]コンテナ[データ] |
| [変更なし]アルゴリズム | find、count、for_each |
| [編集]アルゴリズム | copy、transform、replace |
| [ソート]アルゴリズム | sort + [カスタム比較]関数 |
| [数]valuealgorithm | accumulate([累加]) |
| ラムダ | [匿名]関数,[組み合わせ]アルゴリズム[使用] |
[学習のヒント]:
- [多用]STLアルゴリズム,[少用]ループ
- [よく使う]アルゴリズム、[ドキュメントを参照してあまり使わないもの]
- [式]Lambda[式],code[より簡潔]
📝 練習問題
-
**初心者(難易度 ⭐):[vectorint を作成し]、[10個の乱数]を[格納し]、[sort を使って][並べ替えた後]出力し、[reverse を使って][逆順にした後]出力する。
-
**中級(難易度 ⭐⭐):[用] find [在] vectorstring [中查找指定]string,[用] count [统计某个]value[出现的次数]。
-
**上級(難易度 ⭐⭐⭐):[用] remove_if [と] lambda [を用いて]「[ベクトル] 内のすべての偶数を削除する」という操作を実装する。[erase-remove の慣用表現]を理解する。
- STLアルゴリズム[操作]イテレータ[範囲],[コンテナと]非結合
- [常用]アルゴリズム:ソート/検索/カウント/コピー/逆順
- アルゴリズム[分]クラス:[読み取り専用](find/count)、[書き込み](copy/fill)、[ソート](sort)
- ラムダ [式を]アルゴリズム[として] [パラメータの記述が簡潔になる]
- アルゴリズム+ラムダ式は、[手書きの]ループよりも[簡潔]で、[安全]である
[次のレッスン]: 演習:OOP[総合](#36)—— [オブジェクト指向の考え方を用いて学生管理システムを再構築する]



