11.2. Поиск наибольшего или наименьшего значения в контейнере
11.2. Поиск наибольшего или наименьшего значения в контейнере
Проблема
Требуется найти максимальное или минимальное значение в контейнере.
Решение
Пример 11.2 показывает, как можно находить максимальные и минимальные элементы контейнера с помощью функций max_element и min_element, определенных в заголовочном файле <algorithm>. Эти функции возвращают итераторы,. которые ссылаются на первый элемент, имеющий самое большое или самое маленькое значение соответственно.
Пример 11.2. Поиск минимального или максимального элемента контейнера
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int getMaxInt(vector<int>& v) {
return *max_element(v.begin(), v.end());
}
int getMinInt(vector<int>& v) {
return *min_element(v.begin(), v.end());
}
int main() {
vector<int> v;
for (int i=10; i < 20; ++i) v.push_back(i);
cout << "min integer = " << getMinInt(v) << endl;
cout << "max integer = " << getMaxInt(v) << endl;
}
Программа примера 11.2 выдает следующий результат.
min integer = 10
max integer =19
Обсуждение
Вероятно, вы заметили, что выполняется разыменование значения, возвращаемого функциями min_element и max_element. Это делается по той причине, что указанные функции возвращают итераторы, а не сами значения, поэтому результат должен быть разыменован. Возможно, вы посчитаете, что такая операция разыменования создает небольшое неудобство, однако это позволяет избежать лишнего копирования возвращаемого значения. Это может быть особенно важно, когда копирование возвращаемого значения обходится дорого (например, если это большая строка).
Обобщенные алгоритмы стандартной библиотеки, несомненно, достаточно полезны, однако более важно уметь самому писать свои собственные обобщенные функции получения минимального и максимального значения, находящегося в контейнере. Допустим, вам нужно иметь одну функцию, которая возвращает минимальные и максимальные значения, модифицируя переданные ей по ссылке параметры вместо возвращения пары значений или какой-нибудь другой структуры. В примере 11.3 продемонстрировано, как это можно сделать.
Пример 11.3. Обобщенная функция, возвращающая минимальное и максимальное значения
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
template<class Iter_T, class Value_T>
void computeMinAndMax(Iter_T first, Iter_T last, Value_T& min, Value_T& max) {
min = *min_element(first, last);
max = *max_element(first, last);
}
int main() {
vector<int> v;
for (int i=10; i < 20; ++i) v.push_back(i);
int min = -1;
int max = -1;
computeMinAndMax(v.begin(), v.end(), min, max);
cout << "min integer = " << min << endl;
cout << "max integer = " << max << endl;
}
В примере 11.3 я написал шаблон функции computeMinAndMax, которая принимает два параметра шаблона: один — это тип итератора, другой — тип минимальных и максимальных значений. Поскольку оба параметра шаблона являются также параметрами функции, компилятор C++ может догадаться, какие два отдельных типа (Iter_T и Value_T) используются, как это я продемонстрировал в рецепте 11.1. Это позволяет мне не указывать явно тип параметров шаблона, как это сделано ниже.
compute_min_max<vector<int>::iterator, int>(...)
При выполнении функций min_element и max_element используется оператор operator< для сравнения значений, на которые ссылаются итераторы. Это значит, что, если итератор ссылается на тип, который не поддерживает этот тип сравнения, компилятор выдаст сообщение об ошибке. Однако функции min_element и max_element можно также использовать с функтором сравнения, определенным пользователем, т.е. с указателем на функцию или с объектом-функцией.
Для функций min_element и max_element необходим специальный функтор, принимающий два значения (они имеют тип объектов, на которые ссылается итератор) и возвращающий значение типа Boolean, показывающее, является ли первое значение меньше, чем второе. Функтор, который возвращает значение типа Boolean, называется предикатом. Рассмотрим, например, поиск самого большого элемента в наборе пользовательских типов (пример 11.4).
Пример 11.4. Поиск максимального элемента для пользовательских типов
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
struct Chessplayer {
ChessPlayer(const char* name, int rating)
: name_(name), rating_(rating) { }
const char* name_;
int rating_;
};
struct IsWeakerPlayer {
bool operator()(const ChessPlayer& x, const ChessPlayer& y) {
return x.rating_ < y.rating_;
};
int main() {
ChessPlayer kasparov("Garry Kasparov", 2805);
ChessPlayer anand("Viswanathan Anand", 2788);
ChessPlayer topalov("Veselin Topalov", 2788);
vector<ChessPlayer> v;
v.push_back(kasparov);
v.push_back(anand);
v.push_hack(topalov);
cout << "the best player is ";
cout << max_element(v.begin(), v.end(), IsWeakerPlayer())->name_;
cout << endl;
}
Программа примера 11.4 выдает следующий результат.
the best player is Garry Kasparov (лучший игрок - Гарри Каспаров)
Функторы
Многие STL-алгоритмы в качестве параметров используют определенные пользователем объекты-функции и указатели на функции. И те и другие называются функторами (functors). Иногда в литературе термин «объект-функция» используется как синоним термина «функтор», однако я использую термин «объект-функция» для обозначения только экземпляров класса или структур, которые перегружают operator(). Какой из двух типов функторов лучше использовать? В большинстве случаев объект-функция более эффективен, потому что большинство компиляторов могут легко его реализовать в виде встроенной функции.
Другая причина применения объекта-функции заключается в том, что он может иметь состояние. Вы можете передавать значения его конструктору, который их сохраняет в соответствующих полях для последующего использования. По выразительным возможностям эти объекты-функции становятся сопоставимы с концепцией замыканий, которая используется в других языках программирования.
Наконец, объекты-функции могут определяться внутри другой функции или класса. Указатели на функции приходится объявлять в области видимости пространства имен.
В примере 11.4 я показал, как в функции max_element можно использовать пользовательский предикат. Этот предикат является объектом-функцией IsWeakerPlayer.
Альтернативой пользовательскому предикату, показанному в примере 11.4, является перегрузка оператора operator< для структуры ChessPlayer. Это хорошо работает в определенных случаях, но предполагает, что самой важной является сортировка игроков по рейтингу. Может оказаться, что более распространенной является сортировка по именам. Поскольку в данном случае выбор метода сортировки может быть произвольным, я предпочитаю не определять оператор operator<.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Значения маски АСЕ
Значения маски АСЕ Модели "пользователь, группа, прочие", которую реализует функция InitUnixSA в большинстве случаев будет вполне достаточно, хотя с использованием тех же базовых методов могут реализовываться и другие модели.Вместе с тем, для этого необходимо знать
Значения функции GMP
Значения функции GMP gmp_initСоздает число GMP.Синтаксис:resource gmp_init(mixed number)Число GMP создается из целочисленного или строкового аргумента.В строке может быть указано число десятеричного или шестнадцатеричного формата. Если это шестнадцатеричный формат, то перед числом должен
Ключи и значения
Ключи и значения array_flipМеняет местами индексы и значения массива.Синтаксис:array array_flip(array arr)Эта функция "пробегает" по массиву и меняет местами его ключи и значения. Исходный массив arr не изменяется, а результирующий массив просто возвращается. Если в массиве присутствовало
Поиск на научных сайтах с использованием платформы Flexum «Поиск по научным сайтам»
Поиск на научных сайтах с использованием платформы Flexum «Поиск по научным сайтам» Тема научного поиска не прошла мимо разработчиков персональных поисковиков. Подробному рассказу о возможностях таких поисковых систем посвящена отдельная глава нашей книги (см. главу 6).
10.1.2. Упражнение на определение наименьшего сопротивления
10.1.2. Упражнение на определение наименьшего сопротивления Допустимый ток коллектора BC548B составляет ICmax=200 мА. Определите, какое наименьшее сопротивление должна иметь лампочка при таком токе коллектора, чтобы ее можно было приводить в действие с помощью схемы,
11.1. Подсчет количества элементов в контейнере
11.1. Подсчет количества элементов в контейнере ПроблемаТребуется найти количество элементов в контейнере.РешениеПодсчитать количество элементов в контейнере можно при помощи функции-члена size или функции distance, определенной в заголовочном файле <algorithm>, как это
Значения по умолчанию
Значения по умолчанию Наш пример проиллюстрировал присваивание константам значений по умолчанию. Константам, появляющимся в описании enum, присваиваются целые числа 0, 1, 2 и т. д. в порядке их расположения. Так, описание enum kids {nippy, slats, skip, nana, liz};присваивает nаnа значение 3.
Присвоенные значения
Присвоенные значения Можно выбирать значения, которые вы хотите присвоить константам, но они должны быть целого типа (включая char). Для этого включите желаемыe значения в описание: enum levels {low = 100, medium = 500, high = 2000};Если вы присваиваете какое-либо значение одной константе и не
1. Пустые значения (Empty-значения)
1. Пустые значения (Empty-значения) Пустое значение – это просто одно из множества возможных значений какого-то вполне определенного типа данных.Перечислим наиболее «естественные», непосредственные пустые значения (т. е. пустые значения, которые мы могли бы выделить
2. Неопределенные значения ( Null-значения)
2. Неопределенные значения (Null-значения) Слово Null используется для обозначения неопределенных значений в базах данных.Чтобы лучше понять, какие значения понимаются под неопределенными, рассмотрим таблицу, являющуюся фрагментом базы данных: Итак, неопределенное
3. Значения по умолчанию
3. Значения по умолчанию Системы управления базами данных могут иметь возможность создания любых произвольных значений по умолчанию или, как их еще называют, умолчаний. Эта операция в любой среде программирования имеет достаточно большой вес, ведь практически в любой
Яндекс. Поиск – быстрый поиск документов
Яндекс. Поиск – быстрый поиск документов Документы, как известно, имеют премерзкое свойство накапливаться. И чем больше документов, тем труднее в их залежах найти нужный. Электронные документы здесь не слишком отличаются от бумажных. Проблема места для хранения, правда,
Это не имеет значения
Это не имеет значения Только сутьНаш любимый ответ на вопрос «Почему вы не сделали это или почему вы не сделали то?». Всегда такой: «Поскольку это не имеет значения».Когда мы запустили Campfire, мы слышали некоторые из этих вопросов от людей, впервые проверяющих
4.6.4 Возврат Значения
4.6.4 Возврат Значения Из функции, которая не описана как void, можно (и долно) возвращать значение. Возвращаемое значение задается опратором return. Например:int fac(int n) (*return (n»1) ? n*fac(n-1) : 1; *)В функции может быть больше одного оператора return: int fac(int n) (* if (n » 1) return n*fac(n-1); else return 1; *)Как и
Глава 12 Поиск с предпочтением: эвристический поиск
Глава 12 Поиск с предпочтением: эвристический поиск Поиск в графах при решении задач, как правило, невозможен без решения проблемы комбинаторной сложности, возникающей из-за быстрого роста числа альтернатив. Эффективным средством борьбы с этим служит эвристический
Поиск в Интернете: бои местного значения
Поиск в Интернете: бои местного значения Евгений Овсянников Китай превратился в страну с самым многочисленным Интернет-сообществом – 298 млн. пользователей по сравнению с 227 млн. в США. И самая популярная поисковая служба в Китае – не Google, а Baidu, основанная в Пекине в