Программирование >>  Немодифицирующие последовательные алгоритмы 

1 ... 45 46 47 [ 48 ] 49 50 51 ... 78


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. Мы можем использовать их другими способами. Например, вместо



1 ... 45 46 47 [ 48 ] 49 50 51 ... 78

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика