- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Шрифт:
Интервал:
Закладка:
21.2.1. Примеры использования обобщенных алгоритмов
Алгоритм find() является обобщенным. Это значит, что его можно применять к разным типам данных. Фактически его обобщенная природа носит двойственный характер.
• Алгоритм find() можно применять к любой последовательности в стиле библиотеки STL.
• Алгоритм find() можно применять к любому типу элементов.
Рассмотрим несколько примеров (если они покажутся вам сложными, посмотрите на диаграммы из раздела 20.4).
void f(vector<int>& v,int x) // работает с целочисленными векторами
{
vector<int>::iterator p = find(v.begin(),v.end(),x);
if (p!=v.end()) { /* мы нашли x */ }
// ...
}
Здесь операции над итераторами, использованные в алгоритме find(), являются операциями над итераторами типа vector<int>::iterator; т.е. оператор ++ (в выражении ++first) просто перемещает указатель на следующую ячейку памяти (где хранится следующий элемент вектора), а операция * (в выражении *first) разыменовывает этот указатель. Сравнение итераторов (в выражении first!=last) сводится к сравнению указателей, а сравнение значений (в выражении *first!=val) — к обычному сравнению целых чисел.
Попробуем применить алгоритм к объекту класса list.
void f(list<string>& v,string x) // работает со списком строк
{
list<string>::iterator p = find(v.begin(),v.end(),x);
if (p!=v.end()) { /* мы нашли x */ }
// ...
}
Здесь операции над итераторами, использованные в алгоритме find(), являются операциями над итераторами класса list<string>::iterator. Эти операторы имеют соответствующий смысл, так что логика их работы совпадает с логикой работы операторов из предыдущего примера (для класса vector<int>). В то же время они реализованы совершенно по-разному; иначе говоря, оператор ++ (в выражении ++first) просто следует за указателем, установленным на следующий узел списка, а оператор * (в выражении *first) находит значение в узле Link. Сравнение итераторов (в выражении first!=last) сводится к сравнению указателей типа Link*, а сравнение значений (в выражении *first!=val) означает сравнение строк с помощью оператора != из класса string.
Итак, алгоритм find() чрезвычайно гибкий: если мы будем соблюдать простые правила работы с итераторами, то сможем использовать алгоритм find() для поиска элементов в любой последовательности любого контейнера. Например, с помощью алгоритма find() мы можем искать символ в объекте класса Document, определенного в разделе 20.6.
void f(Document& v,char x) // работает с объектами класса Document
{
Text_iterator p = find(v.begin(),v.end(),x);
if (p!=v.end()) { /* мы нашли x */ }
// ...
}
Эта гибкость является отличительной чертой алгоритмов из библиотеки STL и делает их более полезными, чем многие люди могут себе представить.
21.3. Универсальный алгоритм поиска: find_if()
Нам редко приходится искать какое-то конкретное значение. Чаще нас интересует значение, удовлетворяющее определенным критериям. Мы смогли бы выполнять намного более полезную операцию find, если бы могли определять свои собственные критерии поиска. Например, мы могли бы найти число, превышающее 42. Мы могли бы также сравнивать строки, не учитывая регистр (верхний или нижний).
Кроме того, мы могли найти первое нечетное число. А может, мы захотели бы найти запись с адресом "17 Cherry Tree Lane".
Стандартный алгоритм поиска в соответствии с критерием, заданным пользователем, называется find_if().
template<class In,class Pred>
In find_if(In first,In last,Pred pred)
{
while (first!=last && !pred(*first)) ++first;
return first;
}
Очевидно (если сравнить исходные коды), что он похож на алгоритм find(), за исключением того, что в нем используется условие !pred(*first), а не *first!=val; иначе говоря, алгоритм останавливает поиск, как только предикат pred() окажется истинным, а не когда будет обнаружен элемент с заданным значением.
Предикат (predicate) — это функция, возвращающая значение true или false. Очевидно, что алгоритм find_if() требует предиката, принимающего один аргумент, чтобы выражение pred(*first) было корректным. Мы можем без труда написать предикат, проверяющий какое-то свойство значения, например “содержит ли строка букву x”, “превышает ли число значение 42” или “является ли число нечетным?” Например, мы можем найти первое нечетное число в целочисленном векторе.
bool odd(int x) { return x%2; } // % — деление по модулю
void f(vector<int>& v)
{
vector<int>::iterator p = find_if(v.begin(), v.end(), odd);
if (p!=v.end()) { /* мы нашли нечетное число */ }
// ...
}
При данном вызове алгоритм find_if() применит функцию odd() к каждому элементу, пока не найдет первое нечетное число. Аналогично, мы можем найти первый элемент списка, значение которого превышает 42.
bool larger_than_42(double x) { return x>42; }
void f(list<double>& v)
{
list<double>::iterator p = find_if(v.begin(), v.end(),
larger_than_42);
if (p!=v.end()) { /* мы нашли значение, превышающее 42 */ }
// ...
}
Однако последний пример не вполне удовлетворительный. А что, если мы после этого захотим найти элемент, который больше 41? Нам придется написать новую функцию. Хотите найти элемент, который больше 19? Пишите еще одну функцию. Должен быть более удобный способ!
Если мы хотим сравнивать элемент с произвольным значением v, то должны как-то сделать это значение неявным аргументом предиката алгоритма find_if(). Мы могли бы попробовать (выбрав в качестве удобного имени идентификатор v_val).
double v_val; // значение, с которым предикат larger_than_v()
// сравнивает свой аргумент
bool larger_than_v(double x) { return x>v_val; }
void f(list<double>& v,int x)
{
v_val = 31; // устанавливаем переменную v_val равной 31,
// для следующего вызова предиката larger_than_v
list<double>::iterator p =

