Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП (С++) Лекции Бобин.doc
Скачиваний:
57
Добавлен:
08.02.2015
Размер:
625.66 Кб
Скачать

Глава 17. Контейнеры, итераторы, алгоритмы

п.17.1. Контейнеры

Библиотека контейнеров в С++ включает в себя набор шаблонных классов, предназначенных для хранения объектов одинакового типа.

Стандартные контейнеры библиотеки С++ делятся на последовательные и ассоциативные.

Последовательные контейнеры хранят свои элементы в порядке их добавления. К последовательным контейнерам относятся:

  1. Вектор – безопасный массив, определяется классом vector.

  2. Дек – двусторонняя очередь, определяется классом deque.

  3. Список – list.

Ассоциативные контейнеры хранят свои элементы в строго определенном порядке. При добавлении нового элемента содержимое контейнера переупорядочивается.

  1. Множество (set)

  2. Мультимножество (multiset)

  3. Отображение (map)

  4. Мультиотображение (multimap)

Существуют вырожденные варианты контейнеров, которые не имеют встроенных механизмов обхода своих элементов (адаптеры)

stack;

queue;

priority_queue;

п.17.1.1. Последовательные контейнеры

Информация в последовательных контейнерах хранится всегда в том порядке, в каком ее добавляют.

Шаблон vectorрасполагается в заголовочном файле <vector> и реализует логику работы безопасного массива. То есть все элементы вектора располагаются в памяти подряд, в соседних ячейках. Объект классаvectorприменим в большинстве случаев, где применим массив в стиле Си. Процедура индексирования работает чрезвычайно быстро.

Недостаток вектора: при добавлении элемента происходит перераспределение памяти. Операции добавления, вставки, уничтожения элементов, а также связанные с этим процедуры перераспределения памяти реализованы в методах класса. Существует возможность предварительного резервирования памяти. Осуществляется с помощью метода:

reserve(количество_элементов);

Пример:

vector <int> a;

a.reserve(100);

Узнать количество элементов в векторе можно с помощью метода size:

size() const;

Добавлять элементы в вектора и извлекать можно с трех сторон.

Для добавления элемента в начало вектора:

push_front(элемент);

Убрать элемент из начала вектора:

pop_front();

Добавление\удаление в\из конец вектора:

push_back(элемент);

pop_back;

Вставка нового элемента перед указанным:

insert(куда, что);

Удаление элемента из вектора:

remove(диапазон);

Обращение к элементам:

front();

back();

at(индекс);

В отличии от операции индексирования метод at() проверяет корректность индекса и в случае ошибки запускает исключениеout_of_range.

Списокреализует логику работы классического двусвязного списка.

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

Достоинства списка: чрезвычайно быстрые процедуры добавления, вставки, удаления элементов. Недостаток: нет возможности индексирования.

Список поддерживает те же самые операции, что и вектор, кроме индексирования и резервирования.

list <int> b;

Дек(double-endedqueue) – гибрид вектора и списка (список блоков).

Обеспечивается эффективная процедура добавления\удаления элементов и достаточно быстрая процедура индексирования. Дек поддерживает практически все операции, что и вектор (кроме резервирования)

clear() – очистка контейнера

empty() – проверка, пуст ли контейнер

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

Реализуют ряд математических понятий.

Множество – упорядоченный набор элементов, не допускающий повторений (<set>).

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

При добавлении в множество элемента, который там уже есть, ничего не происходит. Поэтому нужно перегрузить оператор ==.

Замечание по последовательным контейнерам:

Для добавления элемента в контейнер у элемента должны быть: конструктор умолчаний, копирования, оператор присваивания, деструктор. При добавлении нового элемента в последовательный контейнер вызывается конструктор копирования для этого элемента. При удалении контейнера или элемента вызывается деструктор для элемента.

insert(элемент) - вставка элемента в контейнер

find(элемент) - поиск элемента в контейнере

remove(элемент) - удаление элемента

Мультимножество – допускает повторение элементов (<multiset>). В мультимножестве все элементы упорядочены, кроме равных. Они не чувствительны к порядку.

Отображение – пары «ключ-значение» (<map>, <multimap>).

Контейнер multimapдопускает одинаковые ключи с разными значениями. Упорядочивание происходит по ключам.

п.17.1.3. Адаптеры

Адаптеры – упрощенные варианты контейнеров, которые не содержат средств перебора элементов (итераторов).

п.17.2. Итераторы

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

vector<int> arr;

arr.push_back(1);

arr.push_back(2);

arr.push_back(3);

vector<int>::iterator i;

for(i = arr.begin(); i != arr.end(); ++i)

cout << (*i) << ‘ ‘;

cout << endl;

Переменная i– итератор, то есть указатель на элемент вектора целых чисел. В каждом контейнереSTLсуществуют методbegin(), который возвращает итератор на первый элемент контейнера иend(), который возвращает итератор на гипотетический, несуществующий элемент, который находится за последним элементом контейнера. Поскольку элемент, который возвращаетend(), не принадлежит контейнеру, с этим элементом нельзя работать. Вообще, этот метод стоит использовать как проверка того, пустой ли контейнер.

Итераторы бывают четырех типов: читающие, пишущие, двунаправленные и производные.

Читающий итератор– итератор, поддерживающий операции разыменования и инкремента. С помощью этого типа итератора можно посмотреть содержимое элемента контейнера, произвести последовательный обход; но нельзя изменить содержимое просматриваемого элемента. В примере х – переменная,i – итератор.

x = *i++;

Пишущий итератор– итератор, поддерживающий те же самые операции и позволяющий изменить содержимое элемента. Такой итератор часто называют последовательным.

*i = x;

Двунаправленный итератор– итератор, позволяющий смотреть и изменять содержимое контейнера, а так же позволяющий производить обход в двух направлениях. То есть поддерживает операцию декримента.

Итератор произвольного доступа– итератор, допускающий непосредственный доступ. То есть это двунаправленный оператор, допускающий операции сложения и вычитания.

Разные контейнеры возвращают разные итераторы. Например, vectorвозвращает итератор произвольного доступа, а список – двунаправленный итератор.

В ассоциативных контейнерах метод поиска find() возвращает итератор на найденный элемент, либо значение, возвращаемое методомend(), если поиск не завершился успехом.

set<int> nums;

nums.insert(1);

nums.insert(2);

nums.insert(3);

if(nums.find(6) == nums.end())

cout << “Числа 6 в множестве нет” << endl;

Итераторы поддерживают операцию косвенной адресации.

vector<Car> garage;

garage.push_back(Car(“BMW”));

garage.push_back(Car(“Волга”));

garage.push_back(Car(“Москвич”));

vector<Car>::iterator itr;

cout << “Наши машины: ” << endl;

for(itr = garage.begin(); tr != garage.end(); ++i)

itr->print();

Итераторы удобно применять при разработке шаблонных функций

template<class Itr>

void print(Itr &begin, Itr &end)

{

Itr i;

for(i = begin; i != end; ++i)

i->print();

}

Airplane hangar[6];

print(hangar + 2, hangar + 6);

Шаблонные функции на подобии функции print() называются обобщенными алгоритмами.

п.17.3. Библиотека алгоритмов

В заголовочном файле <algoritm> есть стандартные алгоритмы обработки содержимого контейнера. Например, есть алгоритмsort(), принимающий на вход адрес начала упорядочиваемого блока, адрес конца и алгоритм упорядочивания(по умолчанию операция «меньше»).

112