Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP.doc
Скачиваний:
13
Добавлен:
25.04.2019
Размер:
1.34 Mб
Скачать

T accumulate(InputIterator first, InputIterator last, t init, Function f);

Здесь first и last задают диапазон значений итератора, а init устанавливает начальное значение (для аддитивных операций это 0, а для мультипликативных – 1), F – функтор, определяющий вид операции.

Пример

vector<int> v;

V.Push_back(2); V.Push_back(5);

cout << accumulate(v.begin(), v.end(), 10, divides<int>());

Кроме рассмотренных алгоритмов, четвертая группа включает также алгоритмы inner_product, partial_sum и adjacent_difference.

9.5. Функторы

Функтором в STL называют объект, класс которого инкапсулирует операцию функционального вызова operator(). Функторы удобно использовать для представления предикатов и других функций, передаваемых алгоритмам (выше в примерах мы уже несколько раз использовали функторы). Простейшими стандартными функторами являются функтор отрицания и функтор суммирования. Их определения даны ниже.

template <class T> // функтор отрицания

struct negate : unary_function<T, T> {

T operator()(const t & X) const { return -X; }

};

template <class T> // функтор суммирования

struct plus : binary_function<T, T, T> {

T operator()(const T & x, const T & y) const { return x + y; }

};

Шаблон negate, представляющий функтор отрицания, открыто наследует от шаблона unary_function, а шаблон plus, соответствующий функтору суммирования, – от шаблона binary_function. Сами эти шаблоны, по сути, не представляют классы, поскольку не определяют никакого поведения, а лишь вводят типы данных для аргументов и результата. Их определения имеют вид:

template <class Arg, class Result> struct unary_function

{

typedef Arg argument_type;

typedef Result result_type;

};

template <class Arg1, class Arg2, class Result> struct binary_function

{

typedef Arg1 first_argument_type;

typedef Arg2 second_argument_type;

typedef Result result_type;

};

Как шаблоны unary_function, binary_function, так и рассмотренные выше (и многие другие) функторы определены в заголовочном файле function.h. В этом файле имеется много разнообразных функторов, в частности, представляющие базовые логические операции, арифметические операции, операции сравнения.

Кроме стандартных функторов, любая программа может содержать определенные пользователем функторы. Примеры таких определений имеются выше. Ниже приведен еще один подобный пример. В нем определяется функтор prod_odd, который возвращает логическое значение. Оно индицирует, является ли произведение аргументов функтора нечетным числом. Сам функтор используется для поиска в списке первых двух смежных значений, произведение которых нечетно.

Пример

template <class T> class prod_odd {

public:

int operator() (const T & v1, const T & v2) {

return v1%2 != 0 && v2%2 != 0;

}

};

...

list<int> l;

// заполняем список значениями

...

list<int>::iterator i = // поиск стандартным алгоритмом adjacent_find

adjacent_find(l.begin(), l.end(), prod_odd<int>());

if (i != l.end())

cout << *i++ << " " *i++;

else cout << "таких значений в списке нет";

9.6. Ассоциативные контейнеры

Ассоциативные контейнеры – это особый вид контейнеров, которые позволяют быстро получать доступ к хранимым в них данным за счет использования механизма ключей. В STL определены следующие виды таких контейнеров: набор (set), мультинабор (multiset), отображение (map), мультиотображение (multimap). Все указанные контейнеры хранят данные сортированными, причем для обеспечения максимальной скорости получения данных в качестве «внутреннего» контейнера они используют дерево специального вида. Отличие между контейнерами set (map) и multiset (multimap) состоит в том, что set и map используют уникальные ключи для идентификации данных, а multiset и multimap нет. Для того чтобы включить поддержку рассматриваемых контейнеров, нужно подключить заголовочные файлы set.h и map.h соответственно.

Шаблон set инкапсулирует свойства и операции над упорядоченным набором объектов. Ключевые данные для упорядочения – сами хранимые объекты (т.е. хранимый объект – это и данные, и ключ). Параметрами шаблона являются: тип хранимых объектов (он же – тип ключа), функтор Compare, задающий способ упорядочения объектов (по умолчанию упорядочением управляет стандартный функтор less<T>), а также аллокатор, инкапсулирующий модель памяти программы. Число, порядок и назначение параметров шаблона multiset аналогичны (ключи в multiset, напомним, необязательно уникальны, т.е. multiset может содержать один и тот же объект многократно). Примеры определения набора и мультинабора даны ниже (создать контейнер рассматриваемых классов можно также из другого ассоциативного контейнера, или из последовательности элементов с указанием диапазона значений итератора).

Примеры

set < MyClass, greater<MyClass> > MyClassSet;

// порядок сортировки данных задается классом greater<MyClass>

multiset <MyClass> MyClassMultiSet;

// а здесь порядок задается классом less<MyClass> по умолчанию

Контейнеры set и multiset включают «типичные» для всех контейнеров компонентные функции begin, end, rbegin, rend, empty, size, max_size, swap и ряд других. Действие этих функций не отличается от действия их аналогов в последовательных контейнерах. Для перебора компонент set и multiset используют двунаправленные итераторы. Присваивание выполняется операцией operator =, а сравнение операцией operator ==. Добавление объектов производится функцией insert, удаление – функцией erase. К контейнерам set и multiset применимы теоретико-множественные операции, такие как пересечение, включение элемента, разность и т.д.

Пример

struct ltstr // функтор для сравнения объектов

{

bool operator()(const char * s1, const char * s2) const

{

return strcmp(s1, s2) < 0;

}

};

int main() {

const int N = 6;

const char * a[N] = {"aaa", "bbb", "ccc", "ddd", "eee", "fff"};

const char * b[N] = {"zzzz", "eee", "ddd", "tt", "ff", "uuu"};

// формируем наборы из массивов

set<const char *, ltstr> A(a, a + N);

set<const char *, ltstr> B(b, b + N);

// создаем пустой контейнер для результата

set<const char *, ltstr> C;

cout << "Набор A: ";

copy(A.begin(), A.end(), ostream_iterator<const char *>(cout, " "));

cout << endl;

cout << "Набор B: ";

copy(B.begin(), B.end(), ostream_iterator<const char *>(cout, " "));

cout << endl;

cout << "Объединение: ";

set_union(A.begin(), A.end(), B.begin(), B.end(),

ostream_iterator<const char *>(cout, " "), ltstr());

cout << endl;

cout << "Пересечение: ";

set_intersection(A.begin(), A.end(), B.begin(), B.end(),

ostream_iterator<const char *>(cout, " "), ltstr());

cout << endl;

set_difference(A.begin(), A.end(), B.begin(), B.end(),

inserter45(C, C.begin()), ltstr());

cout << "Набор C (разность A и B): ";

copy(C.begin(), C.end(), ostream_iterator<const char *>(cout, " "));

cout << endl;

return 0;

}

Важной особенностью контейнеров set и multiset является то, что вставка и удаление для них не нарушают корректность итераторов на другие элементы. Кроме того, из-за особого внутреннего представления контейнеров эти операции выполняются весьма быстро.

Шаблоны map и multimap содержат набор пар, в каждую из которых входят ключ и ассоциированный с ним объект. Параметризуются они четырьмя элементами: типом ключа, типом объекта, функтором сравнения (по умолчанию less<T>) и аллокатором. Примеры определения набора и мультинабора представлены ниже.

Примеры

map < int, MyClass, less<int> > MyClassMap;

multimap < int, MyClass, less<int> > MyClassMultiMap;

Базовые операции для map и multimap соответствуют операциям для set и multiset. Дополнительно шаблон map вводит операцию operator[], которая позволяет по ключу получить ассоциированный с ним объект. Шаблон multimap не вводит каких-либо новых операций.

Ниже приведен пример применения шаблона multimap.

struct ltstr // функтор для сравнения ключей

{

bool operator()(const char * s1, const char * s2) const

{

return strcmp(s1, s2) < 0;

}

};

int main() {

multimap<const char *, int, ltstr> m;

// вставка пар в мультиотображение

m.insert( pair<const char * const, int>("a", 1) );

m.insert( pair<const char * const, int>("c", 2) );

m.insert( pair<const char * const, int>("b", 3) );

m.insert( pair<const char * const, int>("b", 4) );

m.insert( pair<const char * const, int>("a", 5) );

m.insert( pair<const char * const, int>("b", 6) );

// выделение объектов с одинаковыми ключами

cout << "Число объектов с ключом a: " << m.count("a") << endl;

cout << "Число объектов с ключом b: " << m.count("b") << endl;

cout << "Число объектов с ключом c: " << m.count("c") << endl;

// вывод всех объектов

cout << "Элементы m: " << endl;

for ( multimap<const char *, int, ltstr>::iterator it = m.begin();

it != m.end(); ++it )

cout << " [" << (*it).first << ", "

<< (*it).second << "]" << endl;

}

В примере для представления вставляемых компонент использован шаблон pair, который инкапсулирует свойства упорядоченных пар разнотипных объектов. Определяется шаблон pair в заголовочном файле pair.h. Для удобства вместо явного вызова конструктора пар можно было бы использовать функцию make_pair, определенную в файле utility.h.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]