Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Стандартная библиотека шаблонов построена на трех базовых и двух вспомогательных понятиях. К базовым понятиям относятся:



18.

Стандартная библиотека шаблонов построена на трех базовых и двух вспомогательных понятиях. К базовым понятиям относятся:

контейнеры - содержат коллекции (наборы) объектов (элементов контейнеров);

алгоритмы - предназначены для обработки элементов коллекций, представленных контейнерами;

итераторы - обеспечивают универсальный доступ к элементам контейнеров и перебор этих элементов.

Вспомогательными понятиями служат адаптеры и функторы.

STL контейнер — это параметризованный класс, представляемый шаблоном классов. Объект такого параметризованного класса пригоден для включения других объектов.

Для представления различных коллекций (структур данных) в STL определены контейнеры двух видов: последовательные и ассоциативные.

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

Последовательные контейнеры:

deque - дек. Термин происходит от сокращения фразы double-ended queue — двусторонняя очередь. Дек создается как динамический массив, в который можно включать элементы и из которого можно брать элементы с обоих концов. Вставка в произвольную позицию дека — трудоемкая по числу операций и тем самым по времени исполнения процедура. Для применения дека в программу необходимо включить заголовок <deque>.

list - двусвязный список. Каждый элемент списка содержит некоторое значение (данные) и две ссылки (два указателя) - на предыдущий и на последующий элементы списка. Списки не допускают произвольного обращения (доступа) к элементам. Достоинство списка - быстрое выполнение вставки и удаления элемента, размещенного в любой позиции. Требуется только изменение ссылок. Для применения списка в программу необходимо включить заголовок <list>.

vector- вектор - «безопасный», автоматически расширяющийся массив, обеспечивающий произвольный доступ к находящимся в нем элементам. Доступ осуществляется как с помощью индексирования, так и с помощью специального метода at(). Для применения вектора в программу необходимо включить заголовок <vector>.

Вектор — это самый простой контейнер, относящийся к классу упорядоченных коллекций и реализованный в памяти в виде динамического массива, элементы которого хранятся в определенном порядке и занимают непрерывную область памяти с возможностью расширения с конца. В силу такой организации vector обеспечивает произвольный доступ к своим элементам. Итераторы вектора являются итераторами произвольного доступа (т. е. позволяют передвигаться по контейнеру в обоих направлениях на произвольное количество элементов), поэтому к вектору применимы все алгоритмы STL.



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

v[0]

v[1]

 

 

 

 

 

 

v[n]

 

Рис.1. Структура контейнера vector


 

При работе с контейнерами вместо указателей используются итераторы, выполняющие те же функции, но организованные в виде встроенных классов, что позволяет обеспечить корректную работу со всеми контейнерами. Для итераторов перегружены основные операции, имитирующие их поведение как обычных указателей. Одной из особенностей итераторов является соглашение, по которому, при указании интервала, итератор конца показывает не на последний элемент, а на элемент, лежащий после последнего, даже если физически таковой отсутствует. Такой интервал называется полуоткрытым и обозначается: [begin,end).

Чтобы использовать вектор в программе, необходимо подключить заголовочный файл:

#include <vector>

Описание класса vector, как и всей стандартной библиотеки, лежит в стандартной области имен std.

В программе же, при описании переменной типа vector, необходимо конкретизировать тип хранимых данных, например: vector<int> v.

 

Операции с векторами

Операции с векторами рассмотрим по группам, составив соответствующие таблицы: конструкторы, немодифицирующие операции, операции сравнения, операции присваивания, доступ к элементам вектора, итераторы вектора, вставка и удаление элементов.

 

Таблица 1. Конструкторы

Операция

Назначение

vector<T> v

Создает пустой вектор

vector<T> v(n)

Создает вектор из n элементов

vector<T> v2(vl)

Создает копию вектора vl

vector<T> v2(n,elem)

Создает вектор из n копий elem

vector<T> v2(begin,end)

Создает вектор из элементов интервала [begin, end) любого контейнера, в том числе и из элементов простого массива

 

Здесь Т — тип данных элементов вектора.

Таблица 2. Немодифицирующие операции

Операция

Назначение

v.size ()

Возвращает размер вектора

v.empty()

Возвращает true, если вектор пуст

v.max_size()

Возвращает максимальный размер вектора

v.capacity()

Возвращает максимально доступный размер вектора без перераспределения памяти

v. reserve()

Увеличивает емкость вектора, если текущая емкость меньше

 

 

Таблица 3. Операции сравнения

Операция

Назначение

v1 == v2

Проверяет равенство двух векторов

v1!= v2

Проверяет неравенство двух векторов

v1 < v2

Проверяет, что v1 < v2

v1 > v2

Проверяет, что v1 > v2

v1 <= v2

Проверяет, что v1 <= v2

v1 >= v2

Проверяет, что v1 >= v2

 

Таблица 4. Операции присваивания

Операция

Назначение

v1 = v2

Присваивает v1 все элементы v2

v.assign(n,elem)

Присваивает n копий elem

v.assign(beg,end)

Присваивает элементы интервала [beg, end)

v1.swap(v2)

Меняет местами содержимое v1 и v2

swap(v1,v2)

То же в форме функции

 

Таблица 5. Доступ к элементам вектора

Операция

Назначение

v[index]

Возвращает элемент с индексом index

v.at(index)

Возвращает элемент с индексом index. Генерируется исключение outofrange при выходе за границы интервала

v.front()

Возвращает первый элемент

v. back ()

Возвращает последний элемент

 

С вектором можно обращаться как с массивом данных, однако имеются и дополнительные возможности. Так, метод at(), возвращая элемент контейнера, обеспечивает контроль выхода индекса за границы допустимого интервала, он порождает исключение при выходе за границу интервала, остальные методы в этой ситуации, как правило, приводят к ошибке времени выполнения. Методы front() и back() возвращают первый и последний элементы вектора.

 

Таблица 6. Итераторы вектора

Операция

Назначение

v. begin ()

Возвращает итератор произвольного доступа первого элемента

v.end()

Возвращает итератор произвольного доступа за последним элементом

v.rbegin()

Возвращает обратный итератор первого элемента для перебора в обратном направлении

v.rend()

Возвращает обратный итератор последнего элемента для перебора в обратном направлении

 

Разработчиками STL приняты соглашения, согласно которым при указании диапазона начальный итератор показывает на первый элемент диапазона, а конечный — на элемент, следующий за последним элементом диапазона. В связи с этим достаточно оригинально решена проблема продвижения по контейнеру в обратном направлении: итератор начала показывает на последний элемент, а итератор конца — на фиктивный элемент, стоящий перед начальным. Их можно было бы назвать "начало конца вектора" и "конец начала вектора".

 

Таблица 7. Вставка и удаление элементов

Операция

Назначение

v.insert(pos,elem)

Вставляет в позицию pos элемент, возвращает позицию следующего элемента

v.insert(pos,n,elem)

Вставляет n элементов elem в позицию pos

v.insert(pos,beg,end)

Вставляет элементы интервала [beg, end) в позицию pos

v.push_back(elem)

Вставляет элемент elem в конец вектора

v.pop_back()

Удаляет последний элемент

v.erase(pos)

Удаляет элемент в позиции pos и возвращает позицию следующего элемента

v.erase(beg,end)

Удаляет все элементы из интервала [beg, end)

v. resize(num)

Приводит контейнер к размеру num

v. resize(num, elem)

Приводит контейнер к размеру num, новые элементы создаются как копии elem

v. clear ()

Удаляет содержимое вектора

 

Контейнер List

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

Списки не поддерживают итераторы произвольного доступа, в них не определены ни оператор индексирования [ ], ни метод at(). Для доступа к элементу списка необходимо перебрать все предшествующие элементы. В связи с этим списки не поддерживают работу с некоторыми алгоритмами. В частности, со списком не может быть реализован алгоритм сортировки, однако список имеет собственные методы сортировки.

Чтобы использовать список в программе, необходимо подключить заголовочный файл list.

Операции со списками рассмотрим по группам, составив соответствующие таблицы: конструкторы, немодифицирующие операции, модифицирующие операции, специальные операции (табл. 8 - 11).

 

Таблица 8. Конструкторы

Операция

Назначение

list<T> lst

Создает пустой список

list<T> lst(n)

Создает список из n элементов

list<T> lst1(lst)

Создает копию списка lst

list<T> lst(n,elem)

Создает список из n копий elem

list<T> lst(beg,end)

Создает список из элементов интервала [beg,end)

 

 

Таблица 9. Немодифицирующие операции

Операция

Назначение

lst.size()

Возвращает размер списка

lst.empty()

Возвращает true, если список пуст

lst.max_size()

Возвращает максимальный размер списка

lst1 == lst2

Проверяет равенство

lst1!= lst2

Проверяет неравенство

lst1 < lst2

Проверяет, что lst1 < lst2

lst1 > lst2

Проверяет, что lst1 > lst2

lst1 <= lst2

Проверяет, что lst1 <= lst2

lst1 >= lst2.

Проверяет, что lstl >= lst2

lst.front()

Возвращает первый элемент

lst.backO

Возвращает последний элемент

lst.begin()

Возвращает итератор первого элемента

lst.end()

Возвращает итератор за последним элементом

lst.rbeginO

Возвращает обратный итератор начала контейнера для перебора в обратном направлении

lst.rend()

Возвращает обратный итератор конца контейнера для перебора в обратном направлении

Таблица 10. Модифицирующие операции

Операция

Назначение

lst1 = lst2

Присваивает списку lst1 все элементы lst2

lst.assign(n,elem)

Присваивает n копий elem

lst.assign(beg,end)

Присваивает контейнеру list элементы интервала

[beg,end)

lst1.swap(lst2)

Меняет местами содержимое lstl и lst2

swap(lstl,lst2)

То же в форме функции

lst.insert(pos,elem)

Вставляет в позицию pos элемент, возвращает позицию следующего элемента

lst.insert(pos,n,elem)

Вставляет в позицию pos n элементов elem

lst.insert(pos,beg,end)

Вставляет элементы интервала [beg, end) с позиции pos

lst.push_back(elem)

Вставляет элемент elem в конец списка

lst.pop_back()

Удаляет последний элемент

lst.push_front(elem)

Вставляет элемент elem в начало списка

lst.pop_front()

Удаляет первый элемент

lst.remove(val)

Удаляет все элементы со значением val

lst.remove_if(op)

Удаляет все элементы, для которых op(elem) возвращает true

lst.erase(pos)

Удаляет элемент в позиции pos и возвращает позицию следующего элемента

lst.erase(beg,end)

Удаляет все элементы из интервала [beg, end) и возвращает позицию следующего элемента

lst.resize(num)

Приводит контейнер к размеру num

lst.resize(num,elem)

Приводит контейнер к размеру num, новые элементы создаются как копии elem

lst.clear()

Удаляет содержимое списка

 

Таблица 11. Специальные операции списка

Операция

Назначение

lst.unique()

Удаляет дубликаты

lst.unique(op)

Удаляет дубликаты, для которых ор возвращает true

lst.splice(pos,lst1)

Перемещает все элементы lst1 в lst перед позицией итератора pos

lst.splice(pos,lst1,pos1)

Перемещает все элементы lst1, начиная с позиции итератора pos1, в lst перед позицией итератора pos

lst.splice(pos,lst1,

beg1,end1)

Перемещает все элементы интервала [beg1,end1) списка lst1 в lst перед позицией итератора pos

lst.sort()

Сортирует все элементы оператором <

lst.sort(op)

Сортирует все элементы по критерию ор

lst.merge(lst1)

Перемещает все элементы lst1 в lst с сохранением сортировки

lst.merge(lstl,op)

Перемещает все элементы lstl в 1st с сохранением сортировки по критерию ор

lst.reverse()

Переставляет все элементы в обратном порядке

 

Итераторы

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

vector<int> L;

мы можем объявить в программе и соответствующий итератор

vector<int>::iterator il = L.begin();

 

Категории итераторов

Итераторы стандартной библиотеки делятся на категории. В библиотеке определено 5 категорий итераторов в порядке повышения «способностей»:

- входной (input) — чтение элементов контейнера в прямом направлении;

- выходной (output) — запись элементов контейнера в прямом направлении;

- прямой (forward) — чтение и запись элементов контейнера в прямом направлении;

- двунаправленный (bidirectional) — чтение и запись элементов контейнера в прямом и обратном направлениях;

- произвольного доступа (random access) — произвольный доступ для чтения и записи элементов контейнера.

На практике для любого контейнера гарантируется двунаправленный итератор.

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

Итераторы могут быть константными и неконстантными. Константные итераторы не используются для изменения элементов контейнера.

Итераторы могут быть действительными (когда итератору соответствует элемент контейнера) и недействительными (при отсутствии соответствия между итератором и элементами контейнера). Итератор может стать недействительным по трем причинам:

- итератор не был инициализирован;

- итератор равен end();

- контейнер, с которым связан итератор, изменил размеры или вовсе уничтожен.

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

Для всех категорий итераторов определены следующие операции (i и j — итераторы):

i++ — смещение вперед (возвращает старую позицию);

++i — смещение вперед (возвращает новую позицию);

i = j — присваивание итераторов;

i == j — сравнение итераторов;

i!= j — сравнение двух итераторов на неравенство;

*i — обращение к элементу;

i->member — обращение к компоненту элемента; эквивалентно операции (*i).member.

Остальные операции, определенные для разных категорий итераторов, представлены в табл.12.

Таблица 12. Операции с итераторами разных категорий

Категория итератора

Операции

Контейнеры

Входной

х=*і — чтение элемента

все

Выходной

*i = х — запись элемента

все

Прямой

х=*і, *i =x

все

Двунаправленный

х= *i, *i = x, --і, і--

все

Произвольного доступа

х =*і, *і = х, --і, і--, і+n, і-n, і+=n, і-=n, і < j, і > j, і <= j, і >= j

все, кроме list

Итераторы вставки позволяют вставлять в существующий пустой контейнер новые элементы. Библиотека предоставляет три вида итераторов вставки:

back_insert_iterator — вставка в конец последовательности (конечный итератор вставки);

front_insert_iterator — вставка в начало последовательности (начальный итератор вставки);

insert_iterator — вставка перед заданным элементом (общий итератор вставки).

Итератор вставки в конец (конечный итератор) работает с любым последовательным контейнером. Итератор вставки в начало (начальный итератор) нельзя использовать с вектором, поскольку вектор не обеспечивает вставку элементов в начало — для него не определен метод push_front(). Третий вид итераторов подходит для любого контейнера.

Обращаться к итераторам вставки непосредственно не слишком удобно, поэтому в библиотеке реализованы функции-обертки в виде шаблонов. Так, «конечный» итератор для контейнера создается функцией back_inserter():

template <class Container»

back_insert_iterator<Container> back_inserter(Container& x);

Аналогичный вид имеет функция front_inserter():

template <class Container»

front_insert_iterator<Container> front_inserter(Container& x);

Потоковые итераторы — это итераторы в виде адаптеров, воспринимающих поток данных в качестве источника или приемника данных. Потоковый итератор ввода читает элементы из потока данных, а потоковый итератор вывода записывает данные в выходной поток.

Потоковый итератор вывода создается одним из двух конструкторов:

- ostream_iterator<T>(stream, delim) — создается итератор, связанный с выходным потоком streamt в котором выводимые значения разделяются строкой delim (тип const char *);

- ostream_iterator<T>(stream) — создается итератор, связанный с выходным потоком stream, в котором выводимые значения не разделяются.

Вывод в поток выполняется операцией присваивания, а «перемещение» — операцией ++, как и «перемещение» итераторов вставки. Можно использовать итератор вывода непосредственно, однако чаще выходной итератор применяется совместно с алгоритмами.

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

- istream_iterator<T>(stream) — создается итератор, связанный с входным потоком stream;

- istream_iterator<T>() — создается итератор конца потока.

Если попытка чтения заканчивается неудачей (например, наступает ситуация end-of-file), потоковый итератор ввода превращается в «конечный» итератор.

Итераторы ввода можно определять отдельными переменными, а можно использовать анонимные непосредственно в качестве аргументов при вызове.

 


Дата добавления: 2015-09-28; просмотров: 23 | Нарушение авторских прав




<== предыдущая лекция | следующая лекция ==>
15. Понятие вины. Формы и виды виныСогласно психологической теории, вина определяется как психическое отношение лица к совершаемому общественно опасному действию или бездействию и его | Городской центр кино и досуга

mybiblioteka.su - 2015-2024 год. (0.053 сек.)