• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

    最終更新日時(UTC):
    が更新

    履歴 編集

    function template
    <algorithm>

    std::ranges::upper_bound

    namespace std::ranges {
      template <forward_iterator I,
                sentinel_for<I> S,
                class T,
                class Proj = identity,
                indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
      constexpr I
        upper_bound(I first,
                    S last,
                    const T& value,
                    Comp comp = {},
                    Proj proj = {}); // (1) C++20
    
      template <forward_range R,
                class T,
                class Proj = identity,
                indirect_strict_weak_order<
                  const T*,
                  projected<iterator_t<R>, Proj>
                > Comp = ranges::less>
      constexpr borrowed_iterator_t<R>
        upper_bound(R&& r,
                    const T& value,
                    Comp comp = {},
                    Proj proj = {}); // (2) C++20
    }
    

    概要

    指定された要素より大きい値が現れる最初の位置のイテレータを取得する

    事前条件

    • [first,last) の要素 e!(value < e) または !comp(value, e) によって区分化されていること。
      つまり、!(value < e) または !comp(value, e)true となる全ての要素 e は、false となる全ての要素よりも左側(first に近い方)になければならない。

    戻り値

    [first, last] 内のイテレータ i のうち、以下の条件を満たす、最も右側(first から遠い方)のもの。

    • [first, i) 内の全てのイテレータ j!(value < *j) または comp(value, *j) == false である。

    (つまり、value より大きい要素のうち最初のものを指すイテレータ。value より大きい要素が無ければ last

    計算量

    最大で log2(last - first) + O(1) 回の比較を行う

    備考

    • 本関数は、本質的に partition_point と等価である。
      具体的には、partition_point(first, last, [value](const T& e) { return !bool(value < e); })、あるいは、partition_point(first, last, [value, comp](const T& e) { return !bool(comp(value, e)); }) とすることで等価の結果が得られる。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    struct X {
      int key;    // プライマリキー
      int value;  // 補助的な値
    };
    
    void push_stable(std::vector<X>& queue, X elem)
    {
      // 挿入対象の値 elem よりも大きい要素の位置、すなわち
      // elem と同値な要素グループの次の位置を検索する。
      auto it = std::ranges::upper_bound(queue, elem.key, {}, &X::key);
      queue.insert(it, elem);
    }
    
    
    int main()
    {
      // この関数単体としての使い方
      {
        // upper_bound で 3 より大きい要素の位置を検索する場合、
        // 3 以下の物と 3 より大きい物がその順に並んでいれば、
        // 必ずしもソートされている必要はない。
        std::vector<int> v = {3, 1, 4, 6, 5};
    
        // 3より大きい要素を二分探索で検索
        auto it = std::ranges::upper_bound(v, 3);
        std::cout << *it << std::endl;
      }
    
      // 応用例:安定順序・優先順位付きキューの実装
      {
        std::vector<X> queue;
        push_stable(queue, {100, 1});
        push_stable(queue, {200, 1});
        push_stable(queue, {300, 1});
        push_stable(queue, {300, 2});
        push_stable(queue, {200, 2});
        push_stable(queue, {100, 2});
    
        // プライマリキー key は同値だが異なる値 value を持つ要素間では
        // キュー queue への要素挿入順序が維持されている。
        // (std::priority_queue クラスでは挿入順序は保持されない。)
        for (const auto& e: queue) {
          std::cout << e.key << ':' << e.value << ' ';
        }
        std::cout << std::endl;
      }
    }
    

    出力

    4
    100:1 100:2 200:1 200:2 300:1 300:2
    

    バージョン

    言語

    • C++20

    処理系

    参照