Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP_otvety_k_ekzamenu.doc
Скачиваний:
61
Добавлен:
13.04.2015
Размер:
786.94 Кб
Скачать

47. Итераторы stl - основные разновидности, итераторы контейнеров, итераторы, не связанные с контейнерами.

Итераторы представляют собой указателеобразные объекты, которые алгоритмы STL используют для обхода последовательности объектов, хранящихся в контейнере. Итераторы занимают центральное место в дизайне STL благодаря их роли посредников между контейнерами и обобщенными алгоритмами. Они позволяют создавать обобщенные алгоритмы без учета того, как именно хранятся последовательности данных, а контейнеры — без необходимости написания большого количества исходного текста работающих с ними алгоритмов. основе STL — разделение итераторов на пять категорий: входные, выходные, однонаправленные, двунаправленные и произвольного доступа. Категории входных итераторов. Основные требования, налагаемые определением категории: чтобы был определен оператор ==, выполняющий проверку на равенство, и чтобы был также определен постфиксный оператор ++ с тем же действием, что и префиксный оператор ++, но возвращающий значение итератора до увеличения . термин “входной итератор” не означает тип. Он указывает семейство типов, каждый из которых удовлетворяет описанным ранее базовым требованиям. Входные итераторы могут использоваться для чтения значений последовательности, но запись при помощи входных итераторов возможна не всегда. Выходные итераторы обладают противоположной функциональностью: они позволяют записывать значения в последовательность, но не гарантируют возможность их чтения. Однонаправленный итератор(forward iterator) — это итератор, который объединяет в себе и входной, и выходной итераторы, тем самым обеспечивая возможность чтения и записи и обхода последовательности в одном направлении. Однонаправленные итераторы обладают также свойством, которое не требуется ни для входных, ни для выходных итераторов: возможностью сохранить однонаправленный итератор и использовать сохраненное значение для повторного прохода из того же положения. Двунаправленный итератор аналогичен однонаправленному итератору, за исключением того, что он допускает обход в обоих направлениях. То есть, двунаправленные итераторы должны поддерживать все операции однонаправленных итераторов, а кроме них — операцию - -, делая возможным обход последовательности в обратном направлении. Итераторы с произвольным доступом должны поддерживать все операции двунаправленных итераторов, плюс следующие :

• прибавление и вычитание целых чисел, выражаемые

• доступ к n-му элементу при помощи выражения;

• двунаправленные “большие переходы”;

• вычитание итераторов;

• сравнения, дающие значения типа b o o l.

48. Классификация алгоритмов стандартной библиотеки. Примеры применения наиболее часто используемых алгоритмов.

Обобщенные алгоритмы STL разделяются на четыре большие категории в соответствии с их семантикой. Неизменяющие алгоритмы над последовательностями работают с контейнерами без модификации их содержимого, в то время как изменяющие алгоритмы над последовательностями обычно модифицируют содержимое контейнеров, с которыми они имеют дело. Связанные с сортировкой алгоритмы включают алгоритмы сортировки и слияния, алгоритмы бинарного поиска и операции над множествами, работающие с упорядоченными последовательностями. Наконец, имеется небольшой набор обобщенных числовых алгоритмов. Неизменяющие алгоритмы над последовательностями — это алгоритмы, которые непосредственно не модифицируют контейнеры, с которыми работают. Они включают алгоритмы для поиска элементов в последовательностях, проверки равенства и пересчета элементов последовательности. Это алгоритмы f in d , a d ja c e n t_ f in d , co u n t, f o r _ e a c h , m ism atch, e q u a l и

s e a r c h . Алгоритм a d j a c e n t_ f in d выполняет сканирование последовательности в поисках пары смежных одинаковых элементов. Когда такая пара найдена, алгоритм возвращает итератор, указывающий на первый элемент пары. Алгоритм c o u n t представляет собой неизменяющий алгоритм, сканирующий последовательность для подсчета количества элементов, равных определенному значению. Обобщенный алгоритм f o r _ e a c h применяет функцию f к каждому элементу последовательности. Алгоритмы m ism atch и e q u a l используются для сравнения двух диапазонов. Каждый из них получает три параметра-итератора: f i r s t l , l a s t l и f i r s t 2 . Алгоритм e q u a l возвращает tr u e , если элементы в соответствующих позициях f i r s t l + / и f i r s t 2 + i иравны для всех позиций f i r s t l + iиз диапазона [ f i r s t l ; l a s t l ) , и f a ls e в противном случае. Алгоритм m ism atch возвращает пару итераторов (тип p a ir ) ,11 f i r s t l + in f i r s t 2 + i, которые представляют собой первые позиции последовательностей, где найдены неодинаковые элементы. Если неодинаковых элементов в соответствующих позициях не обнаружено, возвращается пара итераторов l a s t l и f i r s t 2 + ( l a s t l - f i r s t l ) . Для двух данных диапазонов обобщенный алгоритм s e a r c h находит первую позицию в первом диапазоне, с которой вторая позиция входит в первую в качестве подпоследовательности. Этот алгоритм обобщает функции поиска подстрок наподобие библиотечной функции С strstr .

Пример 5.4. Иллюстрация применения обобщенного алгоритма f in d i f

иех05-04.срр" 97а =

#include <iostream>

#include <algorithm>

#include <cassert>

#include <vector>

using namespace std;

// Определение типа унарного предиката:

class GreaterThanSO {

public:

bool operator()(int x) const { return x > 50; }

};

int main()

{

cout << "Иллюстрация применения обобщенного "

<< "алгоритма find_if." << endl ;

// Создание вектора со значениями

// 0, 1, 4, 9, 16, . . . , 144:

vector<int> vectorl;

for (int i = 0; i < 13; ++i)

vectorl.push_back(i * i);

vector<int>::iterator where;

where = find_if(vectorl.begin(), vectorl.e nd(),

GreaterThanSO());

assert (*where == 64);

cout << " -- Ok." << endl;

return 0;

}

Пример 5.5. Иллюстрация применения обобщенного алгоритма

adj a c e n t f in d

"ех05-05.срр" 976 =

#include <iostream>

#include <string>

#include <algorithm>

#include <cassert>

#include <functional>

#include <deque>

using namespace std;

int main()

{

cout << "Иллюстрация применения обобщенного "

<< "алгоритма adjacent_find." << endl;

deque<string> player(5);

deque<string>::iterator i;

// Инициализация дека:

player[0] = "Pele";

player[1] = "Platini";

player[2] = "Maradona";

player[3] = "Maradona";

player[4] = "Rossi";

// Поиск первой пары одинаковых последовательных имен:

i = adjacent_find(player.begin(), player.e n d ());

assert (*i == "Maradona" && *(i+l) == "Maradona");

// Поиск первого имени, лексикографически большего,

// чем следующее за ним:

i = adjacent_find(player.begin(), player.e n d (),

greater<string>());

assert (*i == "Platini" && *(i+l) == "Maradona");

cout << " -- Ok." << endl;

return 0;

}

Изменяющие алгоритмы модифицируют содержимое контейнеров, с которыми работают.

Например, алгоритм u n iq u e удаляет все последовательные дублирующиеся элементы из последовательности. Другие алгоритмы из этой категории копируют, заполнят, генерируют, замещают и т.п. элементы последовательных контейнеров, с которыми работают.

Обобщенные алгоритмы сору и co p y _ b ack w ard используются для копирования элементов из одного диапазона в другой. Вызов copy(firstl/ lastl, first2) копирует элементы из диапазона [ f i r s t l ; l a s t l ) в [ f i r s t 2 ; l a s t 2 ) и возвращает итератор la s t2 , где la s t2 == f i r s t 2 + ( l a s t l - f i r s t l ) . Алгоритм работает в прямом направлении, копируя исходные элементы в порядке f i r s t l , f i r s t l + 1, ..., l a s t l - 1 ,

так что целевой диапазон может перекрываться с исходным, если последний не содержит f i r s t 2. Так, например, со р у может использоваться для сдвига диапазона на одну позицию влево, но не вправо. Обратное верно для алгоритма copy_backw ard: c°py_backward(firstl, lastl, last2) который копирует элементы из диапазона [ f i r s t l ; l a s t l ) в диапазон [ f i r s t 2 ; l a s t 2 ) и возвращает f i r s t 2 , где f i r s t 2 == la s t2 - ( l a s t l - f i r s t l ). Он работает в обратном направлении, копируя исходные элементы в порядке l a s t l - 1 , l a s t l - 2 , ..., f i r s t l . Таким образом, копирование выполняется корректно, если исходный диапазон не содержит l a s t 2.

Пример 5.10. Демонстрация использования обобщенных алгоритмов сору И copy backward

"ех05- 1 0 .срр" 104 =

#include <iostream>

#include <cassert>

#include <algorithm>

#include <vector>

#include <string>

#include <iostream>

using namespace std;

int main()

{

cout << "Демонстрация использования обобщенных "

<< "алгоритмов сору и copy_backward." << endl;

string s ("abcdefghihklmnopqrstuvwxyz");

vector<char> vectorl(s.begin(), s .end());

vector<char> vector2(vectorl.size());

// Копирование vectorl в vector2:

copy(vectorl.begin(), vectorl.e nd(),

vector2.begin( ) ) ;

assert (vectorl == vector2);

// Сдвиг содержимого vectorl влево на 4 позиции:

copy(vectorl.begin() + 4, vectorl.e nd(),

vectorl.begin());

assert (string(vectorl.begin(), vectorl.end()) ==

string("efghihklmnopqrstuvwxyzwxyz"));

// Сдвиг его же вправо на 2 позиции:

copy_backward(vectorl.begin(), vectorl.e nd() - 2,

vectorl.e nd());

assert (string(vectorl.begin(), vectorl.end()) ==

string("efefghihklmnopqrstuvwxyzwx"));

cout << " -- Ok." << endl;

return 0 ;

}

Первый пример copy выполняет копирование содержимого v e c to r l в v e c to r 2. Второй пример иллюстрирует копирование перекрывающихся диапазонов, сдвигая содержимое v e c to r l влево на четыре позиции. Обратите внимание, что после копирования первые четыре символа, ab ed , оказываются потеряны, а последние четыре, wxyz, повторяются в конце дважды. Пример co p y _ b ack w ard выполняет сдвиг на две позиции вправо; такой сдвиг нельзя выполнить при помощи алгоритма сору. В этом случае первые два символа, e f , повторяются в начале строки, а последние два, yz, будут утеряны. Алгоритмы f i l l и f i l l _ n помещают копии данного значения во все позиции диапазона. Вызов fill(first, last, value) помещает l a s t - f i r s t копий v a lu e в [ f i r s t ; l a s t ). Вызов fill_n(first, n, value) помещает n копий v a lu e в [ f i r s t ; f i r s t + n ) . Алгоритм g e n e r a te заполняет диапазон [ f i r s t ; l a s t ) значениями, которые возвращают l a s t - f i r s t последовательных вызовов функции g en (третий параметр алгоритма g e n e r a te ) . Предполагается, что g en не получает никаких аргументов. Обобщенный алгоритм ran d o m _ sh u f f le случайным образом переставляет элементы из диапазона [ f i r s t ; l a s t ), используя для этого функцию, генерирующую псевдослучайные числа. Перестановки, получающиеся при применении алгоритма ran d o m _ sh u f f le , имеют приблизительно равномерное распределение, т.е. вероятность каждой из N\ перестановок диапазона размером N приблизительно равна \/N\ . Обобщенный алгоритм remove удаляет из диапазона те элементы, которые равны определенному значению. Этот алгоритм устойчивый, т.е. он сохраняет относительный порядок остающихся элементов последовательности. Обобщенный алгоритм r e p la c e заменяет элементы в диапазоне, равные некоторому заданному значению, другим значением. Обобщенный алгоритм r o t a t e выполняет циклический сдвиг диапазона. Вызов r o t a t e (f i r s t , m iddle, la s t) циклически сдвигает элементы в диапазоне [ f i r s t ; l a s t ) влево на m id d le - f i r s t позиций. STL предоставляет три обобщенных алгоритма сортировки,— s o r t, p a r t i a l s o r t и s ta b le _ s o r t. Каждый сортирует последовательность с произвольным доступом и размещает результат в том же контейнере, с которым работает. Алгоритм p a r tia l_ _ s o r t требует константного количества дополнительной памяти, s o r t — логарифмического. Они оба по сути являются алгоритмами, работающими “на месте”, в то время как алгоритм s ta b le _ s o r t может потребовать линейного количества дополнительной памяти. В STL входят четыре обобщенных числовых алгоритма: a c c u m u la te , p a r tia l_ s u m , a d ja c e n t_ d if f e r e n c e и in n e r _ j? r o d u c t. В этом разделе мы рассмотрим примеры ис­

пользования каждого из этих алгоритмов. Обобщенный алгоритм a c c u m u la te суммирует значения из указанного диапазона.

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