|
Программирование >> Немодифицирующие последовательные алгоритмы
int main() { int a[5] = {10, 20, -18, 40, 50}, b[5] = { 2, 2, 5, 3, 1}, result[5]; transform(a, a + 5, b, result, compute!)); for (int i=0; i<5; i++) cout result[i] Вывод: 14 24 -8 46 52 cout endl; return 0; To же относится и к версии transform, которая использует унарный функциональный объект. Например, если мы хотим заменить пять элементов a\i\ целочисленного массива а на значение 1.0/(а[г] * аЩ + 1), используя массив а в качестве источника и приемника одновременно, можно достичь Точно так же, как шаблон plus применяется для операции +), следующие бинарные функциональные объекты minus, multiplies, divides и modulus используются для операций -, *, / и % соответственно. То же самое относится к бинарным функциональным объектам equal to, not equal to, greater, less, greaterequal, less equal, logical and и logical or, которые соответствуют операциям ==, !=, >, <, >==, <=, && и 11, возвращающим булевское значение. Два последних функциональных объекта {logicaljindw logical ог) также обычно применяются к аргументам типа bool. Хотя этот список выглядит внушительно, нам часто для функции transform требуются операции, которые в нем отсутствуют. Тогда мы можем использовать свои собственные функциональные объекты, определив класс, который наследует от шаблона binary Junction либо unary function, как было показано в предыдущем разделе. Например, предположим, что нам опять даны два массива целых чисел а и и мы хотим вычислить значения массива result таким образом: result[i] = a[i] + 2 * b[i] ; (скажем, для значений i = 0,1,4). Следующая программа показывает, как решить эту задачу с помощью специально написанного класса compute: II compute.срр: Алгоритм transform и наш собственный функциональный объект, ♦include <iostream> ♦include <algorithm> ♦include <functional> using namespace std; struct compute: binary function<int, int, int> { int operator!)(int x, int у)const{return x + 2 * y;} 6.6. Адаптеры итераторов Для итераторов существуют два типа адаптеров: итераторы вставки (insert) и обратные (reverse) итераторы. В этом разделе мы встретим несколько типов итераторов из тех, что уже были рассмотрены, а также некоторые другие типы. Итераторы вставки Как видно из программы сору2.срр раздела 1.6, алгоритмы наподобие сору будут работать в режиме вставки, если мы напишем, например: сору (v.begin() , v.endO, inserter(L, i)) ; На самом деле в программах compute.срр и computel.срр нет необходимости в наследовании классов от шаблонов binary function и unary Junction, так как мы не используем наши функциональные объекты совместно с адаптерами. Более того, мы можем заменить функциональные объекты на просто функции, написав вместо определения класса compute следующее: int compute(int х, int у) {return х + 2 * у;} и убрав пару скобок, следующих за идентификатором compute в вызове transform. -Прим. переводчика. этого, применяя класс, производный от шаблона unary Junction\ как показывает следующая программа: computel.срр: Заменим a[i] на 1.0/(a[i] * a[i] + 1) . iinclude <iostream> iinclude <algorithm> iinclude <functional> using namespace std; struct computel: unary function<int, double> { double operator()(int x)const { return 1.0/(x * X + 1);} int mainO { int a[5] = {2, 0, 1, 3, 7}; double b[5]; transform(a, a + 5, b, computel ()) ; for (int i=0; i<5; i++) cout b[i] ; Вывод: 0.2 1 0.5 0.1 0.02 cout endl; return 0; Итератор вставки inserter является общим в том смысле, что мы указываем позицию, в данном примере г, в которой будет происходить вставка элементов. Если вставка в контейнер L должна происходить в конце, мы можем написать L.end(), как в следующей программе: соруЗ.срр: Копирование вектора с помощью итератора вставки. ♦include <iostream> ♦include <vector> ♦include <list> using namespace std; int main() { int a[4] = {10, 20, 30, 40}; vector<int> v(a, a+4); list<int> L(2, 123); copy (v. begin 0 , v.end(), inserter(L, L.endO)); list<int>::iterator i; for (i=L.begin() ; i != L.endO; ++i) cout *i ; Вывод: 123 123 10 20 30 40 cout endl; return 0; Поскольку вставка в конце контейнера является часто встречающейся операцией, для нее существует специальный итератор вставки, называемый back inserter. Приведенная выше программа работает точно так же, если мы заменим вызов алгоритма сору на вызов: сору (v. begin о , v.endO, back; inserter (L) ) ; Так как backinserter всегда добавляет элементы в конец, он требует в качестве единственного аргумента контейнер. Еще один итератор вставки, front iitserter, работает специфическим образом: каждый вставляемый элемент помещается в начале контейнера, что приводит к тому, что значения следуют в обратном порядке. Например, если мы заменим вызов алгоритма сору в программе соруЗ.срр строчкой сору(v.begin о, v.end(), front inserter(L)); программа выведет следующие значения: 40 30 20 10 123 123 До сих пор мы применяли итераторы вставки только в качестве аргументов алгоритмов типа сору и merge. Мы можем использовать их другими способами. Например, вместо
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |