typedef pair
VWIterPar p = equal_range(vw.begin, vw.end, w);
if (p.first != p.second) { // Если equal_range возвращает
// непустой интервал…
… // Значение найдено, p.first
// указывает на первый элемент
// интервала, а p.second -
// на позицию за последним элементом
} else {
… // Значение не найдено, p.first
// и p.second указывают на точку
// вставки искомого значения
}
В этом фрагменте используется только критерий эквивалентности, поэтому он всегда верен.
Другая особенность возвращаемого значения equal_range
заключается в том, что расстояние между двумя итераторами равно количеству объектов в интервале, то есть количеству объектов, эквивалентных искомому объекту. В результате equal_range
не только выполняет функции find
для сортированных интервалов, но и заменяет count
. Например, поиск в vw
объектов Widget
, эквивалентных w
, с последующим выводом их количества может выполняться следующим образом:
VWIterPair р = equal_range(vw.begin, vw.end, w);
cout << "There are " << distance(p.first, p.second)
<< " elements in vw equivalent to w.";
До настоящего момента предполагалось, что в интервале ищется
некоторое значение, но есть ситуации, в которых возникает задача поиска Timestamp
, отсортированный от «старых» объектов к «новым»:
class Timestamp {…};
bool operator<(const Timestamp& lhs, //Проверяет, предшествует ли
const Timestamp& rhs); // объект lhs объекту rhs по времени
vector
… // и отсортировать так, чтобы
sort(vt.begin, vt.end); // "старые" объекты предшествовали "новым"
Предположим, из vt
требуется удалить все объекты, предшествующие некоторому пороговому объекту ageLimit
. В данном случае не нужно искать в vt
объект Timestamp
, эквивалентный ageLimit
, поскольку объекта с точно совпадающим значением может и не быть. Вместо этого в vt
ищется граничная позиция, то есть первый элемент, не старший ageLimit
. Задача решается элементарно, поскольку алгоритм lowebound
предоставляет всю необходимую информацию:
Timestamp ageLimit;
…
vt.erase(vt.begin, lower_bound(vt.begin, // Удалить из vt все объекты,
vt.end, // предшествующие значению
ageLimit)); // ageLimit
Слегка изменим условия задачи. Допустим, требуется удалить все объекты, предшествующие или равные ageLimit
. Для этого необходимо найти первый объект ageLimit
. Для решения задачи идеально подходит алгоритм upper_bound
:
vt.erase(vt.begin, upper_bound(vt.begin, // Удалить из vt все объекты,
vt.end, // предшествующие или
ageLimit)); // эквивалентные ageLimit
Алгоритм upper_bound
также часто применяется при вставке в сортированные интервалы, когда объекты с эквивалентными значениями должны следовать в контейнере в порядке вставки. Рассмотрим сортированный список объектов Person
, в котором объекты сортируются по имени:
class Person {
public:
…
const string& name const;
…
}
struct PersonNameLess:
public binary_function
bool operator(const Person& lhs, const Person& rhs) const {
return lhs.name < rhs.name;
}
};
list
…
lp.sort(PersonNameLess); // Отсортировать lp по критерию
// PersonNameLess