<algorithm> ヘッダ
『C++』の標準ライブラリ <algorithm> は、コンテナ(vector・list・配列など)に対してソート・検索・変換・集計といった汎用操作を提供するアルゴリズム関数群です。ループを自前で書く代わりにこれらの関数を使うことで、コードが短くなり意図も明確に伝わります。
構文
// ========================================
// <algorithm> の代表的な関数の構文
// ========================================
#include <algorithm>
#include <vector>
std::vector<int> v = {5, 3, 1, 4, 2};
// ---- ソート ----
std::sort(v.begin(), v.end()); // 昇順ソートします
std::sort(v.begin(), v.end(), std::greater<int>()); // 降順ソートします
// ---- 検索 ----
// find: 値と一致する最初の要素のイテレータを返します
auto it = std::find(v.begin(), v.end(), 3);
// binary_search: ソート済みコンテナから二分探索します(bool を返します)
bool found = std::binary_search(v.begin(), v.end(), 3);
// ---- 変換 ----
// transform: 各要素に関数を適用して別コンテナへ出力します
std::vector<int> out(v.size());
std::transform(v.begin(), v.end(), out.begin(), [](int x){ return x * 2; });
// ---- カウント・条件判定 ----
int cnt = std::count(v.begin(), v.end(), 3); // 値 3 の個数を数えます
bool any = std::any_of(v.begin(), v.end(), [](int x){ return x > 4; });
bool all = std::all_of(v.begin(), v.end(), [](int x){ return x > 0; });
// ---- 最大・最小 ----
auto maxIt = std::max_element(v.begin(), v.end());
auto minIt = std::min_element(v.begin(), v.end());
// ---- コピー・充填 ----
std::vector<int> dst(v.size());
std::copy(v.begin(), v.end(), dst.begin()); // コピーします
std::fill(dst.begin(), dst.end(), 0); // 全要素を 0 で埋めます
// ---- 削除(erase-remove イディオム) ----
v.erase(std::remove(v.begin(), v.end(), 3), v.end()); // 値 3 を全削除します
// ---- 逆順 ----
std::reverse(v.begin(), v.end()); // 要素を逆順にします
主な関数一覧
| 関数 | 概要 |
|---|---|
| std::sort | 範囲内の要素を昇順(またはカスタム比較関数の順)にソートします。平均計算量は O(n log n) です。 |
| std::stable_sort | sort と同様ですが、等しい要素の相対順序を保持します。 |
| std::find | 範囲内で値と一致する最初の要素のイテレータを返します。見つからない場合は end() を返します。 |
| std::find_if | 述語(bool を返す関数)を満たす最初の要素のイテレータを返します。 |
| std::binary_search | ソート済みの範囲から二分探索を行い、値が存在するかどうかを bool で返します。 |
| std::transform | 各要素に関数を適用し、結果を出力イテレータへ書き出します。 |
| std::count | 範囲内で指定した値と一致する要素の個数を返します。 |
| std::count_if | 述語を満たす要素の個数を返します。 |
| std::any_of | 述語を満たす要素が1つでもあれば true を返します。 |
| std::all_of | 全要素が述語を満たせば true を返します。 |
| std::none_of | 述語を満たす要素が1つも無ければ true を返します。 |
| std::max_element | 範囲内の最大値を指すイテレータを返します。 |
| std::min_element | 範囲内の最小値を指すイテレータを返します。 |
| std::copy | 範囲の要素を別の範囲へコピーします。 |
| std::fill | 範囲内の全要素を指定した値で埋めます。 |
| std::remove | 指定した値と一致する要素を末尾へ移動し、新しい論理末尾のイテレータを返します。実際にコンテナのサイズを変えるには erase と組み合わせます。 |
| std::reverse | 範囲内の要素を逆順に並べ替えます。 |
| std::unique | ソート済み範囲内の連続した重複要素を除去します。erase と組み合わせて使います。 |
| std::accumulate | <numeric> ヘッダにある関数で、範囲の要素を累積(合計など)します。 |
サンプルコード
yakuza_algorithm.cpp
// ========================================
// yakuza_algorithm.cpp
// 龍が如くの登場人物のデータを使って
// <algorithm> の主要関数を実演するサンプルです
// ========================================
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
// ========================================
// キャラクター情報を保持する構造体です
// ========================================
struct Character {
std::string name; // キャラクター名です
int power; // 戦闘力です
std::string clan; // 所属組織です
};
// ========================================
// キャラクターの情報を1行で表示するヘルパーです
// ========================================
void printCharacter(const Character& c) {
std::cout << c.name << " (戦闘力: " << c.power << ", 所属: " << c.clan << ")" << std::endl;
}
int main() {
// ========================================
// キャラクターデータを用意します
// ========================================
std::vector<Character> characters = {
{"桐生一馬", 9500, "東城会"},
{"真島吾朗", 9200, "東城会"},
{"嶋野雄一", 7800, "嶋野組"},
{"西谷淳二", 6400, "嶋野組"},
{"錦山彰", 8100, "東城会"},
};
// ========================================
// std::sort: 戦闘力の降順にソートします
// ========================================
std::cout << "=== sort: 戦闘力の高い順 ===" << std::endl;
std::sort(
characters.begin(),
characters.end(),
// 比較関数: 戦闘力が大きいほど前に来るよう指定します
[](const Character& a, const Character& b) {
return a.power > b.power;
}
);
for (int i = 0; i < (int)characters.size(); i++) {
printCharacter(characters[i]);
}
std::cout << std::endl;
// ========================================
// std::find_if: 条件を満たす最初の要素を検索します
// ここでは戦闘力が 8000 を超える最初のキャラを探します
// ========================================
std::cout << "=== find_if: 戦闘力 8000 超の最初のキャラ ===" << std::endl;
std::vector<Character>::iterator found = std::find_if(
characters.begin(),
characters.end(),
[](const Character& c) { return c.power > 8000; }
);
if (found != characters.end()) {
std::cout << "見つかりました: ";
printCharacter(*found);
}
std::cout << std::endl;
// ========================================
// std::count_if: 条件を満たす要素の個数を数えます
// 東城会所属のキャラクター数を数えます
// ========================================
std::cout << "=== count_if: 東城会所属の人数 ===" << std::endl;
int tojoCount = std::count_if(
characters.begin(),
characters.end(),
[](const Character& c) { return c.clan == "東城会"; }
);
std::cout << "東城会: " << tojoCount << " 人" << std::endl << std::endl;
// ========================================
// std::transform: 全員の戦闘力を 10% 増加します
// ========================================
std::cout << "=== transform: 全員の戦闘力を 10% 増加 ===" << std::endl;
std::transform(
characters.begin(),
characters.end(),
characters.begin(),
// 戦闘力を 1.1 倍にした新しい Character を返します
[](Character c) {
c.power = static_cast<int>(c.power * 1.1);
return c;
}
);
for (int i = 0; i < (int)characters.size(); i++) {
printCharacter(characters[i]);
}
std::cout << std::endl;
// ========================================
// std::max_element / std::min_element
// 戦闘力の最大・最小のキャラクターを取得します
// ========================================
std::cout << "=== max_element / min_element ===" << std::endl;
std::vector<Character>::iterator maxIt = std::max_element(
characters.begin(),
characters.end(),
[](const Character& a, const Character& b) { return a.power < b.power; }
);
std::vector<Character>::iterator minIt = std::min_element(
characters.begin(),
characters.end(),
[](const Character& a, const Character& b) { return a.power < b.power; }
);
std::cout << "最強: "; printCharacter(*maxIt);
std::cout << "最弱: "; printCharacter(*minIt);
std::cout << std::endl;
// ========================================
// std::all_of / std::any_of / std::none_of
// ========================================
std::cout << "=== all_of / any_of / none_of ===" << std::endl;
bool allStrong = std::all_of(
characters.begin(), characters.end(),
[](const Character& c) { return c.power > 5000; }
);
bool anyElite = std::any_of(
characters.begin(), characters.end(),
[](const Character& c) { return c.power > 10000; }
);
bool noneWeak = std::none_of(
characters.begin(), characters.end(),
[](const Character& c) { return c.power < 3000; }
);
std::cout << "全員 5000 超: " << (allStrong ? "true" : "false") << std::endl;
std::cout << "10000 超がいる: " << (anyElite ? "true" : "false") << std::endl;
std::cout << "3000 未満がいない: " << (noneWeak ? "true" : "false") << std::endl;
std::cout << std::endl;
// ========================================
// 戦闘力の数値リストを作り、sort + unique + erase で重複削除を実演します
// ========================================
std::cout << "=== sort + unique + erase: 重複除去 ===" << std::endl;
std::vector<int> powers = {9500, 8100, 9200, 8100, 7800, 6400, 9500};
std::sort(powers.begin(), powers.end());
powers.erase(std::unique(powers.begin(), powers.end()), powers.end());
std::cout << "重複除去後の戦闘力リスト: ";
for (int i = 0; i < (int)powers.size(); i++) {
std::cout << powers[i];
if (i + 1 < (int)powers.size()) std::cout << ", ";
}
std::cout << std::endl;
return 0;
}
# コンパイルします g++ -std=c++11 yakuza_algorithm.cpp -o yakuza_algorithm # 実行します ./yakuza_algorithm === sort: 戦闘力の高い順 === 桐生一馬 (戦闘力: 9500, 所属: 東城会) 真島吾朗 (戦闘力: 9200, 所属: 東城会) 錦山彰 (戦闘力: 8100, 所属: 東城会) 嶋野雄一 (戦闘力: 7800, 所属: 嶋野組) 西谷淳二 (戦闘力: 6400, 所属: 嶋野組) === find_if: 戦闘力 8000 超の最初のキャラ === 見つかりました: 桐生一馬 (戦闘力: 9500, 所属: 東城会) === count_if: 東城会所属の人数 === 東城会: 3 人 === transform: 全員の戦闘力を 10% 増加 === 桐生一馬 (戦闘力: 10450, 所属: 東城会) 真島吾朗 (戦闘力: 10120, 所属: 東城会) 錦山彰 (戦闘力: 8910, 所属: 東城会) 嶋野雄一 (戦闘力: 8580, 所属: 嶋野組) 西谷淳二 (戦闘力: 7040, 所属: 嶋野組) === max_element / min_element === 最強: 桐生一馬 (戦闘力: 10450, 所属: 東城会) 最弱: 西谷淳二 (戦闘力: 7040, 所属: 嶋野組) === all_of / any_of / none_of === 全員 5000 超: true 10000 超がいる: true 3000 未満がいない: true === sort + unique + erase: 重複除去 === 重複除去後の戦闘力リスト: 6400, 7800, 8100, 9200, 9500
よくあるミス: sort の比較関数で strict weak ordering を違反する
std::sort に渡す比較関数は strict weak ordering を満たす必要があります。「a < b のとき true を返し、等しいときは false を返す」が正しい形です。<= や == を使うと未定義動作になりクラッシュする場合があります。
// NG: 等しいときに true を返してしまう(strict weak ordering 違反)
std::sort(characters.begin(), characters.end(),
[](const Character& a, const Character& b) {
return a.power >= b.power; // 等しいとき true を返すのは誤りです
}
);
// OK: 等しいときは false を返します(strict weak ordering を満たします)
std::sort(characters.begin(), characters.end(),
[](const Character& a, const Character& b) {
return a.power > b.power; // 降順で等しいときは false になります
}
);
よくあるミス: erase-remove イディオムで erase を忘れる
std::remove はコンテナの要素を物理的に削除しません。「不要な要素を末尾側へ追いやり、新しい論理末尾のイテレータを返す」だけです。実際にサイズを縮めるには必ず erase と組み合わせます。
std::vector<int> powers = {9500, 8100, 9200, 8100, 7800};
// NG: remove だけでは要素数は変わりません
std::remove(powers.begin(), powers.end(), 8100);
// powers.size() はまだ 5 のままです
// OK: erase と組み合わせて初めて物理的に削除されます
powers.erase(
std::remove(powers.begin(), powers.end(), 8100),
powers.end()
);
// powers.size() は 3 になります
よくあるミス: accumulate が <numeric> にある
std::accumulate は <algorithm> ではなく <numeric> ヘッダに含まれています。<algorithm> だけをインクルードしてもコンパイルエラーになります。
// NG: <algorithm> だけでは accumulate は使えません #include <algorithm> // std::accumulate(v.begin(), v.end(), 0); // コンパイルエラーになります
// OK: <numeric> を追加でインクルードします
#include <algorithm>
#include <numeric>
std::vector<int> powers = {9500, 9200, 8100, 7800, 6400};
int total = std::accumulate(powers.begin(), powers.end(), 0);
// total == 41000 になります
概要
<algorithm> ヘッダが提供するアルゴリズム関数はイテレータを通じてコンテナの種類を問わず動作するため、std::vector・std::list・生配列など幅広いデータ構造に適用できます。引数として述語(ラムダ式や関数オブジェクト)を渡すことで、ソート順や検索条件を柔軟にカスタマイズできます。std::remove は要素をコンテナから物理的に削除せず「論理末尾」を返すだけなので、erase と組み合わせる「erase-remove イディオム」が基本パターンです。同様に std::unique も erase と組み合わせて使います。アルゴリズム関数を積極的に活用することで、自前のループよりも意図が明確で読みやすいコードを書くことができます。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。