copy(begin(vs), end(vs),
ostream_iterator
}
7. Скомпилируем и запустим программу:
$ ./transforming_items_in_containers
1, 4, 9, 16, 25,
1^2 = 1
2^2 = 4
3^2 = 9
4^2 = 16
5^2 = 25
Как это работает
Функция std::transform
std::copy
, но вместе с копированием элементов в новый диапазон применяет к значению пользовательскую функцию преобразования до того, как итоговый результат будет присвоен итератору по месту назначения.Выполняем поиск элементов в упорядоченных и неупорядоченных векторах
Иногда требуется определить,
Существует несколько стратегий для поиска элементов. В случае отсортированных элементов можно выполнить бинарный поиск — это быстрее, чем проверка всех элементов один за другим. Если элементы не отсортированы, то придется рассмотреть их по порядку.
Типичные алгоритмы поиска STL могут решить задачу обоими способами, поэтому было бы неплохо познакомиться с ними и узнать их характеристики. Данный раздел посвящен алгоритмам std::find
std::equal_range
(бинарный поиск) и их вариациям.Как это делается
В этом примере мы используем алгоритмы линейного и бинарного поиска на небольшом диапазоне данных.
1. Сначала включим все необходимые заголовочные файлы и объявим об использовании пространства имен std
#include
#include
#include
#include
#include
using namespace std;
2. Наш диапазон данных будет состоять из структур типа city
struct city {
string name;
unsigned population;
};
3. Алгоритмы поиска должны уметь сравнивать элементы друг с другом, поэтому перегружаем оператор ==
city
:bool operator==(const city &a, const city &b) {
return a.name == b.name && a.population == b.population;
}
4. Кроме того, мы хотим выводить на экран экземпляры типа city
<<
:ostream& operator<<(ostream &os, const city &city) {
return os << "{" << city.name << ", "
<< city.population << "}";
}
5. Поисковые функции, как правило, возвращают итераторы. Последние указывают на элемент, если таковой был найден, или же на конечный итератор заданного контейнера. В последнем случае нам нельзя получить доступ к такому итератору. Поскольку мы собираемся вывести на экран результаты поиска, реализуем функцию, которая возвращает другой объект функции, инкапсулирующий конечный итератор структуры данных. При использовании этого объекта функции для вывода объектов на экран он сравнит свой итератор-аргумент с конечным итератором, а затем выведет на экран либо сам элемент, либо строку
template
static auto opt_print (const C &container)
{
return [end_it (end(container))] (const auto &item) {
if (item != end_it) {
cout << *item << '\n';
} else {
cout << "
}
};
}
6. Начнем с рассмотрения примера вектора, содержащего названия немецких городов:
int main()
{
const vector
{"Aachen", 246000},
{"Berlin", 3502000},
{"Braunschweig", 251000},
{"Cologne", 1060000}
};
7. С помощью этой вспомогательной функции создадим функцию, выводящую на экран экземпляры типа city
c
: auto print_city (opt_print(c));
8. Используем алгоритм std::find
find
возвращает нам и ее. Однако мы могли бы, например, создать такой перегруженный оператор ==
для структуры city
, который сравнивал бы только названия городов, не зная численности населения. Но это был бы пример плохого стиля программирования. На следующем шаге мы сделаем это по-другому. {
auto found_cologne (find(begin(c), end(c), city{"Cologne", 1060000}));
print_city(found_cologne);
}