std::ranges::lower_bound
| Défini dans l'en-tête <algorithm>
|
||
| Signature d'appel |
||
template< std::forward_iterator I, std::sentinel_for<I> S,
class T, class Proj = std::identity,
std::indirect_strict_weak_order
<const T*, std::projected<I, Proj>> Comp = ranges::less >
constexpr I lower_bound( I first, S last, const T& value,
Comp comp = {}, Proj proj = {} );
|
(1) | (depuis C++20) (jusqu'à C++26) |
template< std::forward_iterator I, std::sentinel_for<I> S,
class Proj = std::identity,
class T = std::projected_value_t<I, Proj>,
std::indirect_strict_weak_order
<const T*, std::projected<I, Proj>> Comp = ranges::less >
constexpr I lower_bound( I first, S last, const T& value,
Comp comp = {}, Proj proj = {} );
|
(depuis C++26) | |
template< ranges::forward_range R,
class T, class Proj = std::identity,
std::indirect_strict_weak_order
<const T*, std::projected<ranges::iterator_t<R>,
Proj>> Comp = ranges::less >
constexpr ranges::borrowed_iterator_t<R>
lower_bound( R&& r, const T& value, Comp comp = {}, Proj proj = {} );
|
(2) | (depuis C++20) (jusqu'à C++26) |
template< ranges::forward_range R,
class Proj = std::identity,
class T = std::projected_value_t<ranges::iterator_t<R>, Proj>
std::indirect_strict_weak_order
<const T*, std::projected<ranges::iterator_t<R>,
Proj>> Comp = ranges::less >
constexpr ranges::borrowed_iterator_t<R>
lower_bound( R&& r, const T& value, Comp comp = {}, Proj proj = {} );
|
(depuis C++26) | |
[first, last) qui est non inférieur à (c'est-à-dire supérieur ou égal à) value, ou last si aucun élément de ce type n'est trouvé.
L'intervalle [first, last) doit être partitionné par rapport à l'expression std::invoke(comp, std::invoke(proj, element), value), c'est-à-dire que tous les éléments pour lesquels l'expression est true doivent précéder tous les éléments pour lesquels l'expression est false. Un intervalle entièrement trié satisfait ce critère.r comme intervalle source, comme si en utilisant ranges::begin(r) comme first et ranges::end(r) comme last.Les entités de type fonction décrites sur cette page sont objets fonction d'algorithmes (informellement appelés niebloids), c'est-à-dire :
- Les listes explicites d'arguments template ne peuvent pas être spécifiées lors de l'appel de l'une d'entre elles.
- Aucune d'entre elles n'est visible par recherche dépendante des arguments.
- Lorsque l'une d'entre elles est trouvée par recherche non qualifiée normale comme le nom à gauche de l'opérateur d'appel de fonction, recherche dépendante des arguments est inhibée.
Paramètres
| first, last | - | la paire itérateur-sentinelle définissant la plage partiellement ordonnée des éléments à examiner |
| r | - | la plage partiellement ordonnée à examiner |
| value | - | valeur à comparer aux éléments projetés |
| comp | - | prédicat de comparaison à appliquer aux éléments projetés |
| proj | - | projection à appliquer aux éléments |
Valeur de retour
Itérateur pointant vers le premier élément qui est non inférieur à value , ou last si aucun tel élément n'est trouvé.
Complexité
Le nombre de comparaisons et d'applications de la projection effectuées est logarithmique par rapport à la distance entre
first
et
last
(au plus
log
2
(last - first) + O(1)
comparaisons et applications de la projection). Cependant, pour un itérateur qui ne modélise pas
random_access_iterator
, le nombre d'incrémentations d'itérateur est linéaire.
Notes
Sur une plage entièrement triée (ou plus généralement, partiellement ordonnée par rapport à
value
) après projection,
std::ranges::lower_bound
implémente l'algorithme de recherche binaire. Par conséquent,
std::ranges::binary_search
peut être implémentée en l'utilisant.
| Macro de test de fonctionnalité | Valeur | Std | Fonctionnalité |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type
|
202403
|
(C++26) | Initialisation par liste pour les algorithmes ( 1,2 ) |
Implémentation possible
struct lower_bound_fn { template<std::forward_iterator I, std::sentinel_for<I> S, class Proj = std::identity, class T = std::projected_value_t<I, Proj>, std::indirect_strict_weak_order <const T*, std::projected<I, Proj>> Comp = ranges::less> constexpr I operator()(I first, S last, const T& value, Comp comp = {}, Proj proj = {}) const { I it; std::iter_difference_t<I> count, step; count = std::ranges::distance(first, last); while (count > 0) { it = first; step = count / 2; ranges::advance(it, step, last); if (comp(std::invoke(proj, *it), value)) { first = ++it; count -= step + 1; } else count = step; } return first; } template<ranges::forward_range R, class Proj = std::identity, class T = std::projected_value_t<ranges::iterator_t<R>, Proj>, std::indirect_strict_weak_order <const T*, std::projected<ranges::iterator_t<R>, Proj>> Comp = ranges::less> constexpr ranges::borrowed_iterator_t<R> operator()(R&& r, const T& value, Comp comp = {}, Proj proj = {}) const { return (*this)(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj)); } }; inline constexpr lower_bound_fn lower_bound; |
Exemple
#include <algorithm> #include <cassert> #include <complex> #include <iostream> #include <iterator> #include <vector> namespace ranges = std::ranges; template<std::forward_iterator I, std::sentinel_for<I> S, class T, class Proj = std::identity, std::indirect_strict_weak_order <const T*, std::projected<I, Proj>> Comp = ranges::less> constexpr I binary_find(I first, S last, const T& value, Comp comp = {}, Proj proj = {}) { first = ranges::lower_bound(first, last, value, comp, proj); return first != last && !comp(value, proj(*first)) ? first : last; } int main() { std::vector data{1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5}; // ^^^^^^^^^^ auto lower = ranges::lower_bound(data, 4); auto upper = ranges::upper_bound(data, 4); std::cout << "found a range [" << ranges::distance(data.cbegin(), lower) << ", " << ranges::distance(data.cbegin(), upper) << ") = { "; ranges::copy(lower, upper, std::ostream_iterator<int>(std::cout, " ")); std::cout << "}\n"; // recherche binaire classique, retournant une valeur uniquement si elle est présente data = {1, 2, 4, 8, 16}; // ^ auto it = binary_find(data.cbegin(), data.cend(), 8); // '5' retournerait end() if (it != data.cend()) std::cout << *it << " trouvé à l'index " << ranges::distance(data.cbegin(), it); using CD = std::complex<double>; std::vector<CD> nums{{1, 0}, {2, 2}, {2, 1}, {3, 0}}; auto cmpz = [](CD x, CD y) { return x.real() < y.real(); }; #ifdef __cpp_lib_algorithm_default_value_type auto it2 = ranges::lower_bound(nums, {2, 0}, cmpz); #else auto it2 = ranges::lower_bound(nums, CD{2, 0}, cmpz); #endif assert((*it2 == CD{2, 2})); }
Sortie :
found a range [6, 10) = { 4 4 4 4 }
8 found at index 3
Voir aussi
(C++20) |
trouve la plage d'éléments correspondant à la valeur donnée en utilisant la recherche binaire (objet fonction d'algorithme) |
(C++20) |
divise une plage d'éléments en deux groupes (objet fonction d'algorithme) |
(C++20) |
localise le point de partition d'une plage partitionnée (objet fonction d'algorithme) |
(C++20) |
trouve le premier élément supérieur à la valeur donnée en utilisant la recherche binaire (objet fonction d'algorithme) |
| trouve le premier élément non inférieur à la valeur donnée en utilisant la recherche binaire (modèle de fonction) |