C++における責任連鎖パターンの高度な応用

1. 要素を変更しないアルゴリズム

コンテナ内の要素を変更しない操作を提供します。

1.1 find と find_if
  • find(start, end, value): 指定値と等しい最初の要素を検索
  • find_if(start, end, predicate): 条件を満たす最初の要素を検索
  • find_end(start, end, sub_start, sub_end): 部分列の最終出現位置を検索

#include <vector>
#include <iostream>

int main() {
    std::vector<int> numbers = {10, 20, 30, 40, 50};

    // 30を検索
    auto it = std::find(numbers.begin(), numbers.end(), 30);
    if (it != numbers.end()) {
        std::cout << "発見値: " << *it << std::endl;
    }

    // 45より大きい最初の要素
    auto it2 = std::find_if(numbers.begin(), numbers.end(), 
        [](int x) { return x > 45; });
    std::cout << "45超の値: " << *it2 << std::endl;

    // 部分列検出
    std::vector<int> subseq = {20, 30};
    auto it3 = std::find_end(numbers.begin(), numbers.end(), 
        subseq.begin(), subseq.end());
    std::cout << "部分列位置: " << std::distance(numbers.begin(), it3) << std::endl;
}
1.2 count と count_if

std::vector<int> values = {5, 15, 25, 15, 35};

// 15の出現回数
int count = std::count(values.begin(), values.end(), 15); 

// 20未満の要素数
int under20 = std::count_if(values.begin(), values.end(), 
    [](int x) { return x < 20; });

2. 要素を変更するアルゴリズム

2.1 copy と copy_if

std::vector<int> source = {100, 200, 300, 400};
std::vector<int> destination(4);

// 全要素コピー
std::copy(source.begin(), source.end(), destination.begin());

// 条件付きコピー
std::vector<int> filtered;
std::copy_if(source.begin(), source.end(), 
    std::back_inserter(filtered), 
    [](int x) { return x > 250; });
2.2 transform

std::vector<int> input = {1, 2, 3};
std::vector<int> output(3);

// 単一範囲変換
std::transform(input.begin(), input.end(), output.begin(),
    [](int x) { return x * x; });

// 二範囲演算
std::vector<int> adder = {10, 20, 30};
std::vector<int> sum(3);
std::transform(input.begin(), input.end(), adder.begin(), sum.begin(),
    [](int a, int b) { return a + b; });

3. ソート関連アルゴリズム

3.1 sort と partial_sort

std::vector<int> data = {9, 7, 5, 3, 1};

// 昇順ソート
std::sort(data.begin(), data.end());

// 降順ソート
std::sort(data.begin(), data.end(), 
    std::greater<int>());

// 部分ソート
std::vector<int> partial = {5, 2, 9, 1, 5, 6};
std::partial_sort(partial.begin(), partial.begin()+3, partial.end());
3.2 nth_element

std::vector<int> nums = {3, 1, 4, 1, 5, 9};
std::nth_element(nums.begin(), nums.begin()+3, nums.end());
// 4番目に小さい値が位置3に配置される

4. 数値演算アルゴリズム

4.1 accumulate

#include <numeric>

std::vector<int> values = {1, 2, 3, 4, 5};
int total = std::accumulate(values.begin(), values.end(), 0);
int product = std::accumulate(values.begin(), values.end(), 1, 
    std::multiplies<int>());
4.2 inner_product

std::vector<int> a = {2, 3, 4};
std::vector<int> b = {5, 6, 7};
int result = std::inner_product(a.begin(), a.end(), b.begin(), 0);

5. その他のアルゴリズム

5.1 generate と generate_n

std::vector<int> vec(5);
int counter = 0;
std::generate(vec.begin(), vec.end(), 
    [&counter]() { return counter++; });

std::vector<int> vec2(5);
counter = 100;
std::generate_n(vec2.begin(), 3, 
    [&counter]() { return counter++; });
5.2 set_operations

std::vector<int> v1 = {2, 4, 6, 8};
std::vector<int> v2 = {4, 8, 12};
std::vector<int> result;

// 和集合
std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), 
    std::back_inserter(result));

// 積集合
result.clear();
std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), 
    std::back_inserter(result));

6. よくある質問

  1. sort と stable_sortの違い
    前者は高速だが不安定(同等要素の順序保証なし)、後者はマージソートを使用し順序を保持
  2. removeとeraseの併用理由
    removeは要素を末尾に移動させるだけで物理削除は行わないため
  3. ソートが必要なアルゴリズム
    二分探索系(binary_searchなど)、集合操作、mergeなど

タグ: std::find std::sort std::accumulate C++ STL アルゴリズム

8月15日 18:16 投稿