std::equal_range
| ヘッダー <algorithm> で定義 |
||
| (1) | ||
template< class ForwardIt, class T > std::pair<ForwardIt, ForwardIt> |
(C++20 以降 constexpr) (C++26まで) |
|
| template< class ForwardIt, class T = typename std::iterator_traits <ForwardIt>::value_type > |
(C++26以降) | |
| (2) | ||
template< class ForwardIt, class T, class Compare > std::pair<ForwardIt, ForwardIt> |
(C++20 以降 constexpr) (C++26まで) |
|
| template< class ForwardIt, class T = typename std::iterator_traits <ForwardIt>::value_type, |
(C++26以降) | |
範囲firstからlastまでの区間[first, last)で、valueに等しいすべての要素を含む範囲を返します。
|
結果は std::lower_bound(first, last, value) および std::upper_bound(first, last, value) の結果です。 次のいずれかの条件が満たされる場合、動作は未定義です。
|
(C++20まで) |
|
std::equal_range(first, last, value, std::less{}) と同等です。 |
(C++20以降) |
- 範囲
[first,last)の任意の要素 elem について、 bool(comp(elem, value)) は !bool(comp(value, elem)) を意味しません。 - 範囲
[first,last)の要素 elem は、 bool(comp(elem, value)) および !bool(comp(value, elem)) という式に関して分割されていません。
目次 |
[edit] パラメータ
| first, last | - | 調査する要素の分割された範囲を定義するイテレータのペア |
| value | - | 要素と比較する値 |
| comp | - | 第一引数が第二引数より前に順序付けられる場合に `true` を返す二項述語。 述語関数のシグネチャは、以下と同等である必要がある。 bool pred(const Type1 &a, const Type2 &b); シグネチャは const & を持つ必要はないが、関数は渡されたオブジェクトを変更してはならず、値カテゴリに関わらず、(おそらく const の) |
| 型要件 | ||
-ForwardIt は LegacyForwardIterator の要件を満たさなければなりません。 | ||
| -`Compare` は BinaryPredicate の要件を満たす必要があります。 Compare を満たす必要はありません。 | ||
[edit] 戻り値
イテレータのペアを含む std::pair。ここで、
-
firstは、範囲[first,last)のうち、valueより前に順序付けられていない最初の要素へのイテレータ(そのような要素が見つからない場合はlast)、および -
secondは、範囲[first,last)のうち、valueより後に順序付けられている最初の要素へのイテレータ(そのような要素が見つからない場合はlast)です。
[edit] 計算量
std::distance(first, last) を N とする
ただし、ForwardItがLegacyRandomAccessIteratorでない場合、イテレータのインクリメント数はNに対して線形になります。std::setおよびstd::multisetのイテレータはランダムアクセスではないため、それらのメンバ関数std::set::equal_range(またはstd::multiset::equal_range)を使用することが推奨されます。
[edit] 注記
std::equal_rangeは、[first, last)が分割されていることのみを要求しますが、このアルゴリズムは通常、[first, last)がソートされている場合に使用され、任意の value に対して二分探索が有効になります。
std::lower_boundおよびstd::upper_boundの要件に加えて、std::equal_rangeはoperator<またはcompが非対称であること(つまり、 a < b と b < a が常に異なる結果を持つこと)を要求します。
したがって、二分探索の中間結果はstd::lower_boundとstd::upper_boundで共有できます。例えば、std::lower_boundの呼び出し結果は、std::upper_boundの呼び出しにおけるfirst引数として使用できます。
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type |
202403 |
(C++26) | アルゴリズム (1,2) のためのリスト初期化 |
[edit] 実装例
| equal_range (1) |
|---|
template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type> constexpr std::pair<ForwardIt, ForwardIt> equal_range(ForwardIt first, ForwardIt last, const T& value) { return std::equal_range(first, last, value, std::less{}); } |
| equal_range (2) |
template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type, class Compare> constexpr std::pair<ForwardIt, ForwardIt> equal_range(ForwardIt first, ForwardIt last, const T& value, Compare comp) { return std::make_pair(std::lower_bound(first, last, value, comp), std::upper_bound(first, last, value, comp)); } |
[edit] 例
#include <algorithm> #include <complex> #include <iostream> #include <vector> struct S { int number; char name; // note: name is ignored by this comparison operator bool operator<(const S& s) const { return number < s.number; } }; struct Comp { bool operator()(const S& s, int i) const { return s.number < i; } bool operator()(int i, const S& s) const { return i < s.number; } }; int main() { // note: not ordered, only partitioned w.r.t. S defined below const std::vector<S> vec{{1, 'A'}, {2, 'B'}, {2, 'C'}, {2, 'D'}, {4, 'G'}, {3, 'F'}}; const S value{2, '?'}; std::cout << "Compare using S::operator<(): "; const auto p = std::equal_range(vec.begin(), vec.end(), value); for (auto it = p.first; it != p.second; ++it) std::cout << it->name << ' '; std::cout << '\n'; std::cout << "Using heterogeneous comparison: "; const auto p2 = std::equal_range(vec.begin(), vec.end(), 2, Comp{}); for (auto it = p2.first; it != p2.second; ++it) std::cout << it->name << ' '; std::cout << '\n'; using CD = std::complex<double>; std::vector<CD> nums{{1, 0}, {2, 2}, {2, 1}, {3, 0}, {3, 1}}; auto cmpz = [](CD x, CD y) { return x.real() < y.real(); }; #ifdef __cpp_lib_algorithm_default_value_type auto p3 = std::equal_range(nums.cbegin(), nums.cend(), {2, 0}, cmpz); #else auto p3 = std::equal_range(nums.cbegin(), nums.cend(), CD{2, 0}, cmpz); #endif for (auto it = p3.first; it != p3.second; ++it) std::cout << *it << ' '; std::cout << '\n'; }
出力
Compare using S::operator<(): B C D Using heterogeneous comparison: B C D (2,2) (2, 1)
[edit] 不具合報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| LWG 270 | C++98 | Compare は Compare を満たす必要があり、`T` はLessThanComparable (厳密弱順序が必要) である必要がありました。 |
分割のみが必要。 異種比較が許可される。 |
| LWG 384 | C++98 | 最大 2log2(N)+1回の比較が許可されていましたが、これは実装不可能です[1]。 許可されていましたが、これは実装不可能です[1] |
2log2(N)+O(1)に修正されました。 |
- ↑ 単一要素の範囲に
equal_rangeを適用するには2回の比較が必要ですが、計算量の要件では最大1回の比較しか許可されませんでした。
[edit] 関連項目
| 与えられた値より小さくない最初の要素へのイテレータを返す (関数テンプレート) | |
| 特定の値より大きい最初の要素へのイテレータを返す (関数テンプレート) | |
| 部分的に順序付けられた範囲に要素が存在するかどうかを判断する (関数テンプレート) | |
| 要素の範囲を2つのグループに分割する (関数テンプレート) | |
| 2つの要素の集合が同じかどうかを判断する (関数テンプレート) | |
| 特定のキーに一致する要素の範囲を返す ( std::set<Key,Compare,Allocator>のメンバ関数) | |
| 特定のキーに一致する要素の範囲を返す ( std::multiset<Key,Compare,Allocator>のメンバ関数) | |
| (C++20) |
特定のキーに一致する要素の範囲を返す (アルゴリズム関数オブジェクト) |