mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие...

61
Федеральное государственное бюджетное образовательное учреждение Высшего профессионального образования «Пермский Государственный Национальный Исследовательский Университет» Кафедра Прикладной математики и информатики Шеина Т.Ю. Использование библиотеки STL Учебно-методическое пособие по дисциплине «Алгоритмизация программирование II» для студентов 1 курса механико- математического факультета специальности «Прикладная математика и информатика»

Transcript of mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие...

Page 1: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

Федеральное государственное бюджетное образовательное учреждениеВысшего профессионального образования

«Пермский Государственный Национальный Исследовательский Университет»

Кафедра Прикладной математики и информатики

Шеина Т.Ю.

Использование библиотеки STL

Учебно-методическое пособие по дисциплине «Алгоритмизация программирование II» для студентов 1 курса механико-

математического факультета специальности «Прикладная математика и информатика»

г. Пермь 2016

Page 2: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

2

Аннотация

Учебное пособие предназначено для студентов 1 курса механико-

математического факультета, изучающих язык программирования С++ и

имеющих представление об указателях и динамических структурах данных

(список, очередь, стек, дек и т.д.). В пособии рассматриваются последовательные

контейнеры vector, deque, list, адаптеры последовательных контейнеров stack и

queue, а также ассоциативные контейнеры map, multimap, set, multiset, bitmap.

Также в пособии описаны основные алгоритмы библиотеки STL.

Введение

STL (Standart Template Library) – стандартная библиотека шаблонов была

разработана сотрудниками компании Hewlett-PackardСтепановым А.А. и Ли М.

совместно с Муссером Д.Р. из Ренсселэровского политехнического института. В

настоящее время Комитет по стандартизации языка С++ сделал STL составной

частью стандартной библиотеки.

Использование STL дает возможность создавать более надежные и более

универсальные программы, сократив время на их разработку. Например, если мы

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

то мы должны выделить память под новый элемент, записать в него значение,

установить связь с головой стека и следующим элементом, то есть примерно

следующий код:MyNode=new(Node);

MyNode->data=x;

MyNode->Next=Head;

Head=MyNode;

Используя библиотеку STL, мы можем записать все это одной командой:MyNode.push(x);

Библиотека содержит пять основных видов компонентов:

Page 3: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

3

контейнер (container), который управляет набором объектов в памяти;

итератор (iterator), который обеспечивает средство доступа к

содержимому контейнера;

алгоритм (algorithm), который определяет какую-либо вычислительную

процедуру;

функциональный объект (functionobject), который инкапсулирует

функцию в объекте для использования другими компонентами;

адаптер (adaptor), который адаптирует компонент для обеспечения

различного интерфейса.

В рамках курса «Алгоритмизация и программирование II» мы будем

рассматривать только первые три компоненты. Рассмотрим эти компоненты

немного подробнее.

Контейнеры делятся на три группы: 1) последовательные контейнеры

(вектор, двусторонняя очередь, список), 2) адаптеры последовательных

контейнеров (стек, очередь), 3) ассоциативные контейнеры (словари и

множества). В каждом контейнере, кроме собственно данных, есть методы для

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

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

Итератор - это некоторый указатель, который может пробегать все

элементы контейнера. Через итератор мы можем получить некоторый элемент

контейнера. Итераторы бывают разных типов: для движения только вперед, для

движения в обе стороны и др.

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

подсистему. При этом почти любой алгоритм может применяться к почти любому

контейнеру. Контейнер же, к которому применяется алгоритм, передается в него в

качестве параметра.

Page 4: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

4

1. . Последовательныеконтейнеры. Итераторы Предикаты

1.1. .Общие сведения о последовательных контейнерах . Понятие итератора Общие методы работы с

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

Последовательные контейнеры поддерживают указанный пользователем

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

векторы (vector), двусторонние очереди (deque) и списки (list).

Вектор (vector)– это структура, эффективно реализующая произвольный

доступ к элементам, а также добавление в конец и удаление из конца. Элементы

вектора хранятся в непрерывном участке памяти.

Двусторонняя очередь (дек, deque) эффективно реализует произвольный

доступ к элементам, а также добавление в оба конца и удаление из обоих концов.

Дек не гарантируется расположение своих элементов в непрерывных участках

памяти.

Список (list) эффективно реализует вставку и удаление элементов в

произвольном месте, но не имеет произвольного доступа к своим элементам.

Элементы списка хранятся в произвольных участках памяти.

Для работы с любым видом последовательного контейнера необходимо

выполнить следующие действия:

1) подключить соответствующую библиотеку с помощью директивы

#include,

2) описать тип элементов одним из следующих способов:vector <тип элементов> имя_вектора;

deque <тип элементов> имя_дека;

list <тип элементов> имя_списка;

Например:Deque <int> myDeque;//объявление дека myDeque целого типа

Page 5: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

5

При работе с последовательными контейнерами можно использовать

итераторы. Итераторы представляют собой указатели на переменную. Они знают,

где находится необходимая нам переменная, и могут "добыть" её из памяти. Для

создания итератора необходимо написать имя контейнера <тип данных> :: iterator имя итератора

Например,vector <float>::iterator beg;

Что мы можем делать с итераторами?

Мы можем получить элемент, на который они ссылаются с помощью

операции разыменования (аналогично работе с указателями): cout<<*cur;

Здесь мы выводим элемент, на который указывает cur. Оператор * позволяет

нам обращаться не к итератору, а к элементу, на который он указывает.

Мы можем перейти к итератору на следующий элемент или дальше:cur++; // перейти к следующему элементу

cur+=10; // <=>cur=cur+10 перейти на 10 элементов вперед

Последовательные контейнеры имеют ряд общих методов для работы с ними.

Для вызова метода необходимо указать имя контейнера и название метода:имя_контейнера.метод([параметры])

Рассмотрим эти методы(здесь p–имя контейнера)

p.begin() – указывает на первый элементконтейнера,

p.end() – указывает на элемент, следующий за последним,

p.rbegin() - указывает на первый элемент в обратной

последовательности (то есть, на последний элемент),

p.rend() – указывает на элемент, следующий за последним, в

обратной последовательности (то есть будет установлен перед первым

элементом).

В качестве результата будет возвращаться итератор текущего элемента.

Page 6: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

6

Рис. 1

p.size() –возвращает размер контейнера, то есть количество

элементов,

p.max_size() –возвращает максимальный размер, который может

иметь контейнер,

p.empty() –возвращает true, если контейнер пуст и falseв противном

случае,

p.swap(r) –обменивает поэлементно содержимое контейнеров p и r,

p.push_back(t) –вставляет копию значения t в конец контейнера,

p.pop_back() –удаляет из контейнера последний элемент,

p.back() –возвращает значение последнего элемента контейнера.

p.clear() –очищает контейнер, удаляя из него все элементы

Пример 1 #include <iostream>#include <vector>using namespace std;void main(){vector <int> k;// Объявляем вектор целых чисел// Добавляем шесть элементов в конец вектораk.push_back(22);k.push_back(11);k.push_back(4);k.push_back(13);

Page 7: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

7

k.push_back(5);k.push_back(8);vector <int>::iterator p;//Объявляем итератор p// Устанавливаем итератор в начало и передвигаем его в цикле на следующую позициюfor (p = k.begin(); p <k.end(); p++)// Выводим содержимое элементов вектора через разыменованный //итератор cout<<*p<< " ";p=k.begin();// Устанавливаем итератор в началоp+=4;//Переводим итератор на 4 элемента впередcout<<*p;//Выводим текущий элементcout<<k.size()<<"\n"; //выводим размер контейнераcout<<k.max_size()<<"\n"; //выводим максимальный размер контейнераcout<<k.back()<<"\n"; //выводим значение последнего элементаk.pop_back(); //удаляем последний элементcout<<k.back()<<"\n"; //выводим значение последнего элементаk.clear(); //удаляем последний элементif (k.empty()) cout<<"Контейнер пуст"; //проверяем контейнер на //пустотуelse cout<<"Контейнер не пуст";

}Результат:22 11 4 13 5 8 5610737418238Контейнер пуст

Помимо рассмотренных методов данные контейнеры имеют методы insert и

erase для вставки и удаления элементов в произвольное место контейнера, но, так

как они эффективно работают только в контейнере list, мы их рассмотрим в

соответствующей главе.

Page 8: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

8

1.2. Контейнер vector

Вектор (vector) – это динамический массив произвольного доступа с

автоматическим изменением размера при добавлении и удалении

элементов.Доступ к любому элементу вектора осуществляется по индексу за

постоянное время O(1). Добавление элементов в конец вектора и удаление

элементов с конца тоже занимает постоянное время O(1). Однако операции

добавления и удаления элементов из произвольного места вектора зависят от его

размера и требуют времени O(n), поэтому их использование при работе с

вектором не рекомендуется.

Не забывайте, что перед началом работы с любым видом контейнера

необходимо подключать соответствующую библиотеку!

#include <vector>- подключение библиотеки vector

Рассмотрим способы создания и начальной инициализации вектора.

1) Для создания пустого контейнера типа вектор необходимо записать:vector <тип элементов> имя_вектора;

2) Для создания вектора из определенного количестваэлементов можно

использовать два варианта:vector <тип элементов> имя_вектора(n);

vector <тип элементов> имя_вектора(n,t);

В первом случае будет создан вектор из n элементов, инициализированных

значением по умолчанию, которое зависит от типа вектора. Во втором случае

будет создан вектор из n элементов, значения которых будут равны t.

Например:vector <int> k(10);//вектор из 10 элементов, равных 0

vector <int> k(10,5); //вектор из 10 элементов, равных 5

Page 9: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

9

3) Можно инициализировать вектор уже существующими значениями из

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

записать:vector <тип элементов> имя_вектора(i,j);

Здесь i - итератор первого элемента копируемого диапазона, а j–итератор

элемента, следующего за последним элементом копируемого диапазона.

Например:vector <int> k(m.begin()+2,m.end()-1);

В данном примере в вектор k будут скопированы элементы вектора m,

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

mсодержал элементы 2,5,6,7,12,11, то вектор kбудет содержать элементы 6, 7, 12.

Теперь рассмотрим методы добавления новых элементов в вектори их

удаления:

k.push_back(t) –вставляет копию значения t в конец контейнера;

k.pop_back() –удаляет из контейнера последний элемент;

k.insert(p,t) –вставляет значение t перед элементом, на который

указывает итератор p;

k.insert(p,n,t) –вставляетn копий значения t перед элементом, на

который указывает итератор p;

k.insert(p,i,j) – вставляет копию диапазона [i,j) перед элементом,

на который указывает итератор p (здесь i и j тоже итераторы);

k.erase(p) – удаляет элемент, на который указывает итератор p;

k.erase(p,q) – удаляет элементы из диапазона [p,q), где pи q–

итераторы;

k.clear() – очистка вектора,

k.resize(n,t) – изменяет контейнер так, что он содержит ровно

nэлементов (лишние элементы будут удалены, а если элементов,

наоборот, меньше чем n, то будут добавлены значения, равные t)

Page 10: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

10

k.resize(n) – изменяет контейнер так, что он содержит ровно n

элементов (лишние элементы будут удалены, а если элементов,

наоборот, меньше чем n, то будут добавлены значения, равные значению

по умолчанию)

Еще раз обращаем внимание на то, что методы insert и erase работают

неэффективно, поэтому их использование нежелательно. Кроме того, после

выполнения операций insert и erase в контейнере vector итератор становится не

определен, и при попытке обратиться с помощью него к элементу будет

выдаваться ошибка!!

Пример 2 #include<iostream>#include<vector>using namespace std;void main(){setlocale(LC_ALL, "Russian");// Объявляем вектор из целых чиселvector <int> k;int a;// Объявляем итератор.vector <int>::iterator p;// Вводим 5 элементов и помещаем их в конец вектораfor (int i=1; i<=5; i++){

cin>>a;k.push_back(a);

}for (p = k.begin(); p <k.end(); p++) { // Выводим содержимое элементов вектора cout<<*p<<" "; }cout<<"\n";

Page 11: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

11

k.insert(k.begin()+2,2,0);//вставляем перед третьим элементом вектора два 0for (p = k.begin(); p <k.end(); p++) {// Выводим содержимое элементов вектора cout<<*p<<" "; }cout<<"\n";k.insert(k.begin(),k.begin()+2,k.end());//копируем в начало вектора элементы с третьего до последнегоfor (p = k.begin(); p <k.end(); p++) {// Выводим содержимое элементов вектора

cout<<*p<<" "; }k.erase(k.begin(),k.begin()+5); //удаляем первые 5 элементов вектораcout<<"\n";for (p = k.begin(); p <k.end(); p++) {// Выводим содержимое элементов вектора

cout<<*p<<" "; }}Вводим 1 2 3 4 5Результат:1 2 3 4 51 2 0 0 3 4 50 0 3 4 5 1 2 0 0 3 4 51 2 0 0 3 4 5

Можно также занести в вектор значение, используя оператор присваивания:

K[5]=6 //присвоить элементу вектора с номером 5 значение 6

Page 12: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

12

Для извлечения определенного элемента вектора используются следующие

варианты:

k.back() – извлечь последний элемент

k[n] – извлечь элемент с номером n

k.at(n) – извлечь элемент с номером n (альтернативный вариант)

Так как вектор всегда располагается в непрерывном участке памяти, то при

добавлении в него новых элементов возможна ситуация, когда существующего

размера непрерывного блока памяти будет не хватать и придется полностью

переписывать весь вектор в новый непрерывный участок памяти, что,

естественно, замедляет работу с вектором. Поэтому удобнее заранее

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

метода reserve:

k.reserve(n) – выделяет непрерывный участок памяти для nэлементов

Для определения объема зарезервированной памяти можно воспользоваться

методом capacity:

k.capacity() – возвращает количество элементов, для которых

зарезервирована память.

Таким образом, метод sizeвозвращает реальное количество элементов в

векторе, а capacity - тот размер, до которого можно добавлять данные без

дополнительного выделения памяти.

Например:vector <int> k;k.reserve(5);cout<<k.size()<<" "<<k.capacity()<<"\n";

Результат: 0 5

Page 13: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

13

1.3. Контейнер deque

Контейнер deque – это двухсторонняя очередь с возможностью быстрой

вставки и удаления элементов, как в ее начало, так и в конец. Несмотря на то, что,

казалось бы, было бы естественным реализовать двухстороннюю очередь с

помощью двусвязного списка, в библиотеке STL она реализована по-другому, что

дает возможность произвольного доступа к элементам очереди (аналогично

вектору). Элементы двухсторонней очереди размещаются в блоках

фиксированного размера, а адреса этих блоков хранятся в специальном массиве

указателей.

Рис. 2

Выполнение команды вставки в начало предполагает, что новый элемент

помещается слева от позиции, обозначенной D.begin(). После неоднократного

выполнения этой операции первый из блоков будет заполнен и будет выделен

следующий блок, который займет место в позиции 0 массива, приведенного на

рис. 2. Аналогичным образом происходи вставка элементов в конец дека. Как

только все блоки будут заполнены, будет выделен больший объем памяти под

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

середине, что снова даст возможность расширять структуру с обеих сторон. Так

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

гарантирует размещение своих элементов в непрерывном участке памяти.

Page 14: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

14

Так как размеры всех блоков строго фиксированы, то адрес любого элемента

двухсторонней очереди может быть вычислен за постоянное время, то есть

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

как уже было сказано ранее.

#include <deque>- подключение библиотеки deque

Начальная инициализация элементов двухсторонней очереди совершенно

аналогична инициализации элементов вектора, только вместо слова «vector»

необходимо писатьdeque:deque <тип элементов> имя_дека;

deque <тип элементов> имя_дека(n);

deque <тип элементов> имя_дека(n,t);

deque <тип элементов> имя_дека(i,j);

Методы добавления новых элементов в деки их удаления также аналогичны

вектору, за исключением того, что возможна вставка и удаление элементов в

начало дека:

k.push_front() –вставляет копию значения t в начало контейнера;

k.pop_front() –удаляет из контейнера первый элемент;

Методы insert и erase в контейнере deque также как и в контейнере vector,

работают неэффективно, поэтому их использование нежелательно. Кроме того,

после их использования итератор становится не определен!

Для извлечения определенного элемента очереди используются те же

варианты, что и при работе с вектором:

k.back() – извлечь последний элемент

k[n] – извлечь элемент с номером n

k.at(n) – извлечь элемент с номером n (альтернативный вариант).

Кроме того, можно извлечь из очереди первый элемент: k.front()

Page 15: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

15

Пример 3 #include <iostream>#include <deque>using namespace std;

void main(){ setlocale(LC_ALL, "Russian"); // Объявляем дек из целых чисел deque <int> k;int a;// Объявляем итератор. deque <int>::iterator p;// Вводим 5 элементов и помещаем их в конец очереди for (int i=1; i<=5; i++) {

cin>>a;k.push_back(a);

}// Вводим 5 элементов и помещаем их в начало очереди for (int i=1; i<=5; i++) { cin>>a;

k.push_front(a);}for (p = k.begin(); p <k.end(); p++) { // Выводим содержимое элементов очереди cout<<*p<<" "; }cout<<"\n";cout<<"\n"<<k.at(1);}

Page 16: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

16

Вводим 1 2 3 4 5 6 7 8 9 10Результат:10 9 8 7 6 1 2 3 4 59

Обращаем внимание, что для двухсторонней очереди не определены методы

reverse и capacity !!

1.4. Контейнер list. Предикаты

Контейнер list– это двухсвязный список, элементы которого хранятся в

произвольных участках памяти. Преимущество двухсвязных списков перед

векторами и очередям заключается в возможности вставки элементов в

произвольное место списка за постоянное время O(1). Недостаток заключается в

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

Каждый узел списка содержит ссылку на предыдущий и последующий узлы,

то есть к итераторам применимы операции инкремента (++) и декремента (--). Но,

в отличие от вектора и очереди, в списках нельзя использовать операции,

перемещающие итератор сразу на несколько позиций. Это связано с отсутствием

произвольного доступа к элементам. Запись k.erase(k.begin(),k.begin()+5)

будет ошибочна. Таким образом, для перемещения итератора на несколько

позиций придется использовать цикл. Например, для вывода 4-го элемента списка

необходимо записать следующий код:p=k.begin();for (int i=1; i<=3; i++) p=++p;cout<<*p;

Однако благодаря отсутствию перераспределения памяти (как это

происходит при работе с контейнерами vector и deque), после выполнения

операций вставки и удаления элементов итератор сохраняет свое прежнее

значение:p=++k.begin();k.insert(k.begin(),k.begin(),k.end());

Page 17: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

17

cout<<*p;

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

vectorиdeque будет выдана ошибка).

Работа со списками во многом аналогична работе с векторами и

двусторонней очередью.Подключение библиотеки list:#include <list>

Начальная инициализация элементов:list <тип элементов> имя_списка;

list <тип элементов> имя_списка(n);

list <тип элементов> имя_списка(n,t);

list <тип элементов> имя_списка(i,j);

Для двухсвязных списков используются все те же методы, что и для

контейнера deque (см. главу 1.3) и плюс некоторые дополнительные методы,

которые мы рассмотрим ниже.

1) Сцепка списков (splice) служит для перемещения элементов из

одного списка в другой без перераспределения памяти, только за счет изменения

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

Существует три варианта вызова данного метода:а) splice(p, L2)

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

позиция которого задана итератором p, все элементы списка L2.Второй список

остается пустым. Нельзя вставить список в самого себя.

Пример 4#include <iostream>#include <list>using namespace std;

void main(){

Page 18: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

18

setlocale(LC_ALL, "Russian");int a;// Объявляем два списка целых чисел list <int> L1,L2;// Объявляем итератор list <int>::iterator p;// Вводим 5 элементов и помещаем их в конец списка L1 for (int i=1; i<=5; i++) {

cin>>a;L1.push_back(a);

}// Вводим 5 элементов и помещаем их в конец списка L2 for (int i=1; i<=5; i++) {

cin>>a;L2.push_back(a);

} p=L1.begin();for (int i=1; i<=3; i++) //переходим к 4-му элементу списка L1

p=++p;L1.splice(p,L2);for (p = L1.begin(); p != L1.end(); p++) {// Выводим содержимое элементов списка L1 cout<<*p<<" "; } cout<<"\n"; if (L2.empty()) cout<<"Список пуст"; else for (p1 = L2.begin(); p1 != L2.end(); p1++) { // Выводим содержимое элементов списка L2 cout<<*p1<<" ";

Page 19: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

19

}cout<<"\n";}Вводим в первый список: 1 2 3 4 5 Вводим во второй список: 6 7 8 9 0Результат:1 2 3 6 7 8 9 0 4 5Список пуст

б) splice(p1,L2,p2);

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

итератор p2 из списка L2 в вызывающий списокперед элементом, на который

указывает итератор p1. Допускается переносить элемент в пределах одного

списка. Например:p2=L1.begin();for (int i=1; i<=3; i++) // Ищем 4-ыйэлемент p2=++p2;p1=L1.begin();L1.splice(p1,L1,p2); // Переносим 4-ыйэлемент в начало спискаfor (p1 = L1.begin(); p1 != L1.end(); p1++) {cout<<*p1<<" ";}Вводим: 1 2 3 4 5 Результат:4 1 2 3 5

в)splice(p1,L2,q1,q2);

Третья форма функции аналогичным образом переносит из спискаL2 в

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

четвертым параметрами функции. Допускается переносить элемент в пределах

одного списка.Если для одного и того же списка первый параметр находится в

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

Page 20: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

20

2) Удаление элементов по значению (remove). Напоминаем, что метод

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

элементов, лежащих в заданном диапазоне.

Метод remove(n) позволяет удалить из списка элементы с заданным

значением. Если таких элементов несколько, то будут удалены все.Например,

команда L.remove(3) удалит все элементы, равные 3.

Метод remove_if(p) позволяет удалить из списка элементы, значение

которых удовлетворяет заданному предикату p.

Предикат – это некоторая логическая функция, которая возвращает либо

true, либо falseдля каждого элемента списка. Если для очередного элемента

функция принимает значение true, то этот элемент будет отобран и с ним будет

выполнено действие (в данном случае удаление), иначе – нет.

Пример 5. Занести в список 10 целых чисел, удалить из него значения,

больше 3 и вывести список на экран#include <iostream>#include <list>using name space std;bool more3 (int k)//функция-предикат для проверки числа{ if (k>3) return true;else return false;}

void main(){ list <int> L; int i,a; list <int>:: iterator p;for (i=1; i<=10; i++){

cin>>a;L.push_back(a);

Page 21: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

21

} L.remove_if(more3); //удаление чисел со значением больше 3for (p=L.begin(); p!=L.end(); p++)

cout<<*p<<" ";}

Обратите внимание, что при работе со списками значение итераторов можно

проверять только на равенство или неравенство. Запись p<L.end() будет

ошибочной. Попробуйте объяснить сами, с чем это связано.

3) Сортировка элементов (sort).

Метод sort()позволяет отсортировать элементы списка по возрастанию.

Для сортировки по убыванию необходимо вызвать метод sort(p), где p–

предикат, определяющий порядок сортировки. Предикат может, например, быть

представлен в виде следующей функции:bool less1(int x, int y){ return y<x;}

При вызове метода необходимо будет записать sort(less1).

4) Изменение порядка следования элементов (reverse).

Метод reverse()позволяет изменить порядок следования элементов списка

на противоположный.

5) Удаление из списка повторяющихся элементов (unique).

а) Метод unique()позволяет удалить все элементы, кроме первого, из

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

вызове этого метода для списка 3 4 4 5 1 2 2 8 8 9 2 4 5 5 получим результат: 3 4 5

1 2 8 9 2 4 5. Обращаем внимание, что будут удалены не все повторяющиеся

Page 22: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

22

элементы, а только те, которые идут подряд. Если необходимо удалить именно

все повторяющиеся значения, то список предварительно нужно отсортировать.

б) Метод unique(p) позволяет удалить из списка все элементы,

удовлетворяющие предикату p при сравнении с последующим элементом. То есть

в функции-предикате обязательно необходимо сравнивать именно два элемента

списка между собой. Например:bool more(int x,int y){if (x>y) return true;else return false;}

При использовании этой функции будут удаляться те элементы списка,

которые меньше предыдущего элемента. То есть, если было введено, например, 3

6 8 1 2 4 9 3 8 10, то при вызове метода с предикатом more получим 3 6 8 9 10.

6) Слияние двух списков (merge).

L1.merge(L2)– сливает два упорядоченных списка L1 и L2 в один

отсортированный список и помещает результат в L1. Список L2 остается пуст.

Обращаем внимание на то, что оба списка должны быть отсортированы в одном и

том же порядке (либо оба по возрастанию, либо оба по убыванию)!

Результирующий список должен сортироваться в том же порядке, что и исходные

списки. Например, если были введены списки 2 5 6 7 и 3 7 9 10 (отсортированные

по возрастанию), то получим первый список 2 3 5 6 7 7 9 10, а второй список

будет пустым. Однако если исходные списки были отсортированы по убыванию

(например, с помощью предиката less1, описанного выше), то и при вызове

метода merge необходимо вызвать этот предикат в следующем виде:L1.merge(L2,less1)

Если этого не сделать, то будет выдаваться ошибка выполнения!

Page 23: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

23

Стандартные предикаты

В библиотеке STL есть набор готовых стандартных предикатов, что

избавляет пользователя от написания собственных избыточных аналогов:

equal_to Бинарный bool x == y

not_equal_to Бинарный bool x != y

greater Бинарный bool x > y

less Бинарный bool x < y

greater_equal Бинарный bool x >= y

less_equal Бинарный bool x <= y

Для вызова стандартных предикатов необходимо записать:название предиката <тип элементов> ()

Например, при выполнении данного кода: L1.sort(greater <int> ());

L2.sort(greater <int> ());L1.merge(L2,greater <int> () );

Списки L1 и L2 будут отсортированы по убыванию, а затем произойдет их

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

Обращаем внимание, что данные стандартные предикаты можно

использовать только в тех методах, где требуется сравнение рядом стоящих

элементов (sort, unique, merge).

Page 24: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

24

2. Адаптерыпоследовательныхконтейнеров

2.1. Понятие адаптера последовательного контейнера

Адаптеры контейнеров - это контейнеры, созданные на основе

существующих контейнеров, но имеющие ограниченный функционал работы.

Адаптеры контейнеров не поддерживают работу с итераторами, то есть в них не

допускается перемещение по элементам. К адаптерам стандартных контейнеров

относятся stack и queue. Оба эти контейнера созданы на основе контейнера deque

и реализуют стандартные действия для работы со стеком и очередью.

2.2. Контейнер stack

Для создания стека нужно подключить библиотеку <stack> и в коде

программы его объявить:stack <тип элементов> имя_стека;

У стека есть немного функций:

push() - добавить элемент

pop() - удалить верхний элемент

top() - получить верхний элемент

size() - размер стека

empty() - true, если стек пуст

Пример 6. Считывать с клавиатуры слова, пока не встретится слово «end» и

вывести их в обратном порядке#include <iostream>#include <string>#include <stack>using namespace std;void main()

Page 25: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

25

{ string s; stack <string> st; s=""; while (s.compare("end")) { cin>>s; st.push(s); } while (!(st.empty())) { cout<<st.top()<<endl; st.pop(); }}

В этом примере мы считываем слова с клавиатуры, пока не встретится слово

«end» и выводим их в обратном порядке.

2.3. Контейнер queue

Очереди, как следует из названия, используют принцип first in first out (FIFO).

То есть, тот элемент, который мы первым занесли в очередь, первым из нее и

выйдет. Реализуются очереди также просто. Подключаем библиотеку <queue>. И

создаем очередь:queue <тип элементов> имя_очереди;

Перечень функций почти тот же, что и у стека:

push() - добавить элемент

pop() - удалить первый элемент

size() - размер очереди

empty() - true, если очередь пуста

front() - получить первый элемент

back() - получить последний элемент

Page 26: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

26

Пример 7. Считывать с клавиатуры слова до тех пор, пока не встретится

слово «end» и вывести их в прямом порядке#include <iostream>#include <string>#include <queue>using namespace std;void main(){ string s; queue <string> st; s=""; while (s.compare("end")) { cin>>s; st.push(s); } while (!(st.empty())) { cout<<st.front()<<endl; st.pop(); }}

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

3.1. Понятие ассоциативного контейнера

Ассоциативные контейнеры обеспечивают быстрый доступ к данным за счет

того, что они, как правило, построены на основе сбалансированных деревьев

поиска (стандартом регламентируется только интерфейс контейнеров, а не их

реализация). Существует пять типов ассоциативных контейнеров: словари (тар),

словари с дубликатами (multimap), множества (set), множества с дубликатами

Page 27: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

27

(multiset) и битовые множества (bitset). Словари часто называют также

ассоциативными массивами или отображениями. В данном пособии мы

рассмотрим первые четыре типа контейнеров.

3.2. Контейнеры map и multimap

Ассоциативные контейнеры обеспечивают быстрый доступ к данным за счет

того, что они, как правило, построены на основе сбалансированных деревьев

поиска (стандартом регламентируется только интерфейс контейнеров, а не их

реализация). Существует пять типов ассоциативных контейнеров: словари (тар),

словари с дубликатами (multimap), множества (set), множества с дубликатами

(multiset) и битовые множества (bitset). Словари часто называют также

ассоциативными массивами или отображениями.

В C++ существует контейнер map, который позволяет хранить в одном

элементе сразу два значения. Например, у вас есть список фамилий учеников и их

средние баллы аттестата или фамилии сотрудников и их стаж работы. Контейнер

map позволяет нам хранить эти данные в виде ключ-значение (например,

фамилия ученика — средний балл, фамилия сотрудника — стаж работы).

Контейнер map является отсортированным массивом, в котором сортировка

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

уникальными значениями ключа! При добавлении нового элемента он

автоматически вставляется в массив таким образом, чтобы не нарушилась

сортировка.

Для использования map вам необходимо сначала его подключить:#include <map>

Для создания контейнера достаточно написать:map <тип ключа,тип данных> имя контейнера;

Например: map <string,int> sotrud;//фамилия, стаж работы

Для доступа (или записи) в массив нужно писать:имя_контейнера[key];

При выполнении данного действия возможны два варианта:

Page 28: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

28

1) Если запись с таким ключом существует, то в качестве результата будет

возвращено соответствующее значение второго поля;

2) Если записи с таким ключом нет, то она будет создана. Если значение

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

Например: int k=sotrud[“Петров”];

Если сотрудник по фамилии Петров имеется среди записей, то в переменную

k будет записан стаж его работы. Если сотрудник с такой фамилией будет

отсутствовать среди записей, то он будет добавлен, а значение второго поля

получит значение по умолчанию, то есть 0.

Если мы запишем sotrud[“Петров”]=10, то если запись с таким ключом

уже имеется, то значение второго поля будет заменено на 10, иначе запись будет

создана и первое (ключевое) поле получит значение «Петров», а второе поле – 10.

Контейнер map также имеет возможность работы с итераторами: map <string,int>:: iterator p;

Для обращения к элементу в строках и векторах достаточно было перед

именем итератора поставить *, но в map так не получится, т.к. в каждом элементе

хранится 2 значения (ключ и данные). Поэтому надо писать так:

(*p).first - для обращения к ключу и (*p).second -для обращения к

данным, где p - итератор элемента

Кроме контейнера map существует контейнер multimap. Его отличие в том,

что мы можем одному ключу задать несколько соответствий, то есть допускается

существование элементов с одинаковыми ключами. Например, автору можно

сопоставить несколько написанных им книг. Для его использования необходимо

также подключить библиотеку map, а для создания контейнера написать:multimap <тип ключа,тип данных> имя контейнера;

Обращаем внимание, что для занесения значения в элемент контейнера

multimap нельзя использовать операцию обращения по ключу

имя_контейнера[key]. Объясните сами, почему? Для добавления новых

элементов в контейнер необходимо использовать метод insert (см.ниже).

Рассмотрим некоторые методы контейнеров map и multimap:

Page 29: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

29

begin() – установить итератор на первый элемент

end() – установить итератор за последним элементом

empty() - true, если контейнер пуст

count(key) – возвращает число элементов с заданным ключом

find(key) – возвращает итератор на элемент с указанным ключом

size() – вычисляет количество элементов в контейнере

clear() - полная очистка контейнера

Пример 8. Подсчитать количество слов в тексте. Текст считывать из

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

частоты встречаемости.#include <iostream>#include <string>#include <map>#include <fstream>using namespace std;void main(){map <string,int> words; //создаем контейнер map, содержащий слово и //количество повторенийifstream in;in.open("in.txt");string word;while (!in.eof()){in>>word; //считываем из файла очередное словоwords[word]++;//Ищем запись с ключом word и увеличиваем значение поля //данных на 1. Если этого слова еще нет, то оно будет добавлено в //контейнер и количество повторений установится равным 1}ofstream out;out.open("out.txt");

Page 30: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

30

map <string,int>::iterator cur;//создаем итератор curout<<"Words count:"<<endl;for (cur=words.begin();cur!=words.end();cur++) //вывод списка слов с указанием частоты встречаемости out<<(*cur).first<<": "<<(*cur).second<<endl;}

Рассмотрим методы, позволяющие удалять элементы из контейнеров map и

multimap:

erase(it) – удаляет элемент, на который указывает итератор it;

erase(k) – удаляет элемент со значение k и в качестве результата

возвращает количество удаленных элементов;

erase(start,end) - удаляет элементы между заданными итераторами

[start,end).

Предлагаем вам разобраться самостоятельно, как работают данные методы.

Методы вставки элементов insert отличаются для контейнеров map и

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

рассмотрению этого метода введем понятие «пары» pair. Класс pair позволяет

объединить в одно целое пару разнородных значений, если между ними есть

какая-то связь. Описание класса pair:pair <тип 1-го элемента, тип 2-го элемента> имя_переменной

Чтобы обратиться к первому элементу пары, необходимо указать

имя_переменной.first, а ко второму элементу – имя_переменной.second.

Теперь рассмотрим методы вставки элементов для контейнера map:

insert(pair <тип_ключа, тип_данных> (key,data)) – вставляет пару

значений (key,data) в контейнер, если он не содержит элемента с таким же

ключом key. Обращаем внимание на отличие от добавления элементов с

помощью операции обращения по ключу имя_контейнера[key]=значение. В

последнем случае, если элемент с таким ключом существует, то его значение

будет заменено. В случае использования insert этого не произойдет. Метод insert

Page 31: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

31

возвращает в качестве результата пару P такую, что P.first – итератор,

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

P.second возвращает значение true, если элемент был добавлен, и false, если нет

(то есть элемент с таким значением уже был в контейнере). В этом случае

переменная P должна быть описана с помощью объекта pair.

Пример 9// Создаем контейнер sort, содержащий фамилию и стаж работыmap <string,int> sotr; // Объявляем итераторыmap <string,int>::iterator p;// Объявляем пару для возвращаемого значения insert, состоящего из итератора и //логического значенияpair <map <string,int>::iterator,bool> q;// Вводим 5 элементов for (int i=1; i<=5; i++) {

cin>>s;cin>>a;

// Добавляем элемент в контейнерq=sotr.insert(pair <string,int> (s,a));

// Проверяем наличие элемента с заданным ключомif (!q.second) cout<<"Элемент уже существует";else cout<<"Элемент добавлен";

}

insert(i,j) – вставляет значения из диапазона [i,j), если они не

содержатся в контейнере.

Пример 10 p=++sotr2.begin();q=--sotr2.end();sotr1.insert(p,q);

insert(p, pair <тип_ключа, тип_данных> (key,data)) –

вставляет пару значений (key,data) в контейнер, если он не содержит

Page 32: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

32

элемента с таким же ключом. p – это итератор, являющийся рекомендацией,

с какого элемента следует начать поиск. Следует отметить, что, если при

поиске с указанного итератора элемент не будет найден, то все равно будет

просмотрен весь контейнер, так как вставка элемента с дублирующим

значением ключа невозможна. Этот итератор позволяет лишь ускорить

поиск, если вставляемый элемент попадает в заданный диапазон. В отличие

от первого варианта вставки элемента (pair <тип_ключа, тип_данных>

(key,data)) в качестве результата будет возвращаться итератор,

указывающий на элемент с заданным ключом key. Например:

Пример 1 1 map <string,int> sotr1; // Объявляем итераторыmap <string,int>::iterator p,q;// Вводим 5 элементовfor (int i=1; i<=5; i++) {

cin>>s;cin>>a;sotr1.insert(pair <string,int> (s,a));

}// Перемещаем указатель на второй элементp=++sotr1.begin();// Добавляем элемент, если он не существуетq=sotr1.insert(p,pair <string,int> ("А",10));// Выводим элемент с заданным ключом (либо существующий, либо добавленный)cout<<(*q).second;

Методы вставки элементов для контейнера multimap аналогичны, за

исключением того, что вставка происходит всегда, вне зависимости от наличия

элемента с заданным ключом в контейнере.

Page 33: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

33

Рассмотрим еще три общих для контейнеров map и multimap метода:

upper_bound(key) – устанавливает итератор на первый элемент, ключ

которого больше указанного

lower_bound(key) – устанавливает итератор на первый элемент, ключ

которого больше или равен указанному

equal_range(key) – возвращает пару P такую, что [P.first, P.second) –

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

значение key. Если таких элементов нет, то возвращается пустой диапазон.

Пример 1 2 #include <iostream>#include <map>#include <string>#include "windows.h"using namespace std;

void main(){ SetConsoleCP(1251); SetConsoleOutputCP(1251); int a; string s; multimap <string,int> sotr; multimap <string,int>::iterator p;// Создаем тип it – итератор на контейнер multimap

typedef multimap <string,int>::iterator it; for (int i=1; i<=5; i++) {

cin>>s;cin>>a;sotr.insert(pair <string,int> (s,a));

} // Описываем пару pair, содержащую два итератора

pair <it,it> rez;

Page 34: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

34

// Ищем диапазон значений с ключом «Петров» rez=sotr.equal_range("Петров"); p=rez.first;// Выводим значение, на которое указывает первый итератор

cout<<(*p).second; p=--rez.second;// Выводим значение, на которое находится перед вторым //итератором

cout<<(*p).second; for (p = sotr.begin(); p != sotr.end(); p++) { cout<<(*p).first<<(*p).second<<" "; } cout<<"\n";}

3.3. Контейнеры set и multisetМножество set является ассоциативным контейнером, который хранит

объекты типа «ключ», то есть в контейнере этого типа не может быть одинаковых

элементов. Так же как и map, контейнер типа set является отсортированным

массивом.

Для использования set необходимо сначала подключить библиотеку:#include <set>

Для создания контейнера достаточно написать:set <тип ключа> имя контейнера;

Например: set <string> sotrud;//фамилия

К контейнеру set применимы практически все те же методы, что и к

контейнеру map:

begin() – установить итератор на первый элемент

end() – установить итератор за последним элементом

empty() - true, если контейнер пуст

count(key) – возвращает число элементов с заданным ключом

find(key) – возвращает итератор на элемент с указанным ключом

Page 35: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

35

size() – вычисляет количество элементов в контейнере

clear() - полная очистка контейнера

erase(it) – удаляет элемент, на который указывает итератор it;

erase(k) – удаляет элемент со значение k и в качестве результата

возвращает количество удаленных элементов;

erase(start,end) - удаляет элементы между заданными итераторами

[start,end).

upper_bound(key) – устанавливает итератор на первый элемент, ключ

которого больше указанного

lower_bound(key) – устанавливает итератор на первый элемент, ключ

которого больше или равен указанному

equal_range(key) – возвращает пару P такую, что [P.first, P.second) –

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

значение key. Если таких элементов нет, то возвращается пустой диапазон.

insert(key) – вставляет значение key в контейнер, если он не содержит

элемента с таким же ключом key. Метод insert возвращает в качестве результата

пару P такую, что P.first – итератор, указывающий на элемент с ключом key

(добавленный или уже существующий), а P.second возвращает значение true, если

элемент был добавлен, и false, если нет (то есть элемент с таким значением уже

был в контейнере).

insert(i,j) – вставляет значения из диапазона [i,j), если они не

содержатся в контейнере.

insert(p, key) – вставляет значение key в контейнер, если он не

содержит элемента с таким же ключом. p – это итератор, являющийся

рекомендацией, с какого элемента следует начать поиск. Следует отметить,

что, если при поиске с указанного итератора элемент не будет найден, то

все равно будет просмотрен весь контейнер, так как вставка элемента с

дублирующим значением ключа невозможна. Этот итератор позволяет

лишь ускорить поиск, если вставляемый элемент попадает в заданный

Page 36: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

36

диапазон. В качестве результата будет возвращаться итератор,

указывающий на элемент с заданным ключом key.

Пример 13 #include <iostream>

#include <set>

using namespace std;

void main ()

{

//======== Создаем множество целых чисел

set <int> s;

s.insert(1);

s.insert(2);

s.insert (3);

//======= Повторно вставляем единицу (она не пройдет)

s.insert (1);

//==== Два раза вставляем "в конец последовательности"

s.insert(--s.end(),4);

s.insert(--s.end(),-1);

set <int>::iterator cur;//создаем итератор

for (cur=s.begin();cur!=s.end();cur++) //вывод

cout<<*cur<< " ";}

Получим

-1 1 2 3 4

Page 37: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

37

Множество multiset тоже является ассоциативным контейнером, который

хранит объекты типа «ключ», но в контейнере этого типа могут быть одинаковые

элементы. Все методы множества multiset аналогичны подобным методам

множества multmap. Предлагаем вам самостоятельно разобраться с их работой.

4. Алгоритмы

Как уже было сказано ранее, алгоритмы не являются частью контейнеров, а

образуют отдельную подсистему. При этом почти любой алгоритм может

применяться к почти любому контейнеру. Контейнер же, к которому применяется

алгоритм, передается в него в качестве параметра.

Для того, чтобы можно было использовать алгоритмы, необходимо

подключить библиотеку algorithm:

#include <algorithm>

Рассмотрим основные алгоритмы.

4.1. Алгоритмыпоиска и подсчетаВсе алгоритмы поиска возвращают итератор на элемент, а не сам элемент.

find(begin,end,what) - ищет первый элемент со значением what в

промежутке [begin, end), где begin и end - итераторы соответствующего

контейнера. Если соответствующее значение не найдено, то итератор будет

установлен на элемент end (отметим, что он в диапазон поиска не входит).

Пример 14 #include <iostream>#include <list>#include <algorithm>#include "windows.h"using namespace std;void main()

Page 38: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

38

{ SetConsoleCP(1251); SetConsoleOutputCP(1251); int a; list <int> note; list <int>::iterator p,q,t; for (int i=1; i<=10; i++) {

cin>>a;note.push_back(a);

} p=++note.begin(); q=--note.end(); t=find(p,q,3); cout<<*t<<" ";}

В этом примере вводится 10 целых чисел и дальше в диапазоне от 2-го числа

до 9-го (включительно) ищется значение 3. Рассмотрим, что будет возвращать

алгоритм при разных исходных данных:

Вариант 1. 3 4 5 6 7 8 9 0 1 2, результат - 2 (значение не найдено, возвращен

элемент с итератором q, то есть последний)

Вариант 2. 4 5 3 6 7 8 3 0 1 2, результат - 3 (значение найдено)

Вариант 3. 4 5 3 6 7 8 3 0 1 3, результат - 3 (значение в диапазоне от 2-го до

9-го элемента не найдено, возвращен элемент с итератором q, то есть последний)

find(begin,end,pred) - ищет первый элемент, удовлетворяющий

заданному предикату pred (про предикаты было сказано в главе 1.4) в

промежутке [begin, end), где begin и end - итераторы соответствующего

контейнера. Если соответствующее значение не найдено, то итератор будет

установлен на элемент end.

adjacent_find(start,end) - ищет два последовательных совпадающих

элемента между start и end и возвращает итератор на первый из них. Например,

если будет дан список с именем note, в который введена последовательность 1 2 3

Page 39: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

39

3 4 5 5 6, то после выполнения команды

t=adjacent_find(note.begin(),note.end()) итератор будет установлен на

элемент с номером 2.

search(start,end,sbegin,send) - ищет между start и end

последовательность sbegin-send. Возвращает итератор, указывающий на начало

найденной последовательности.

Пример 15 p=++note1.begin();q=--note1.end();t=search(note2.begin(),note2.end(),p,q);

count(sbegin,send,d) - подсчет количества элементов со значением d в

промежутке sbegin – send.

count_if(sbegin,send,pred) - подсчет количества элементов в

промежутке sbegin – send, удовлетворяющих предикату pred

max_element(sbegin,send) – возвращает итератор на максимальный

элемент диапазона [sbegin,send)

min_element(sbegin,send,pred) - возвращает итератор на минимальный

элемент диапазона [sbegin,send)

4.2. Алгоритмы сортировкиОбращаем внимание, что приведенные ниже алгоритмы сортировки

работают только с контейнерами произвольного доступа (vector, deque)!!

sort(start,end) - сортирует элементы диапазона [start,end) в порядке

возрастания.

sort(start,end, pred) - сортирует элементы диапазона [start,end) в

порядке, заданном с помощью предиката pred.

reverse(start,end) - инвертирует элементы последовательности start-end.

random_shuffle(start,end) - сортирует элементы между start и end в

случайном порядке

Page 40: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

40

sort(start,end) - сортирует элементы диапазона [start,end) в порядке

возрастания. Работает только с контейнерами произвольного доступа (vector,

deque)!!

is_sorted(start,end) – возвращает логическое значение true, если

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

is_sorted(start,end,pred) – возвращает логическое значение true, если

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

функцией-предикатом.

4.3. Алгоритмыудаления и замены remove(begin,end,what) - в промежутке begin-end удаляет все элементы,

равные значению what. Но при этом нужно учитывать, что размер

последовательности не меняется, то есть освобождения памяти не происходит. В

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

за диапазоном итоговой последовательности.

Пример 16. Пусть в список введены значения 5 3 6 3 7 3 8 3 9 0. Дан код:q=remove_if(note1.begin(),note1.end(),3);cout<<*q<<" "<<"\n";for (p = note1.begin(); p != end(); p++) { cout<<*p<<" "; }

Получим следующий результат:8

5 6 7 8 9 0 8 3 9 0

То есть теоретически после удаления всех элементов, равных 3, в списке

должно остаться 6 элементов: 5 6 7 8 9 0, то есть итератор должен указывать на

седьмой элемента списка, который равен 8. «Хвост» списка (элементы 8 3 9 0)

остаются неизменными. Чтобы их не выводить на экран, необходимо изменить

код следующим образом:q=remove_if(note1.begin(),note1.end(),3);cout<<*q<<" "<<"\n";for (p = note1.begin(); p !=q; p++) {

Page 41: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

41

cout<<*p<<" "; }

Тогда получим8

5 6 7 8 9 0

remove_if(begin,end,pred) - в промежутке begin-end удаляет все

элементы, удовлетворяющие значению предиката pred. В остальном работа

алгоритма аналогична алгоритму remove.

unique(begin,end) - удаляет дубликаты последовательно расположенных

элементов. Размер последовательности при этом не меняется, то есть

освобождения памяти не происходит (в отличие от метода unique, который меняет

размер последовательности). В качестве результата будет возвращен итератор на

первый элемент, который лежит за диапазоном итоговой последовательности.

unique(begin,end,pred) - позволяет удалить из списка все элементы,

удовлетворяющие предикату p при сравнении с последующим элементом. То есть

в функции-предикате обязательно необходимо сравнивать именно два элемента

списка между собой. Размер последовательности при этом не меняется, то есть

освобождения памяти не происходит. В качестве результата будет возвращен

итератор на первый элемент, который лежит за диапазоном итоговой

последовательности.

Пример 16. Пусть в список введены значения 3 6 7 9 12 4 6 9 10 14. Дан код:...bool more3(int x,int y){

return (x-y>2);}...q=unique(note1.begin(),note1.end(),more3);for (p = note1.begin(); p != q; p++) { cout<<*p<<" "; }

Получим следующий результат:3 6 7 9 12 10 14

Page 42: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

42

replace(begin,end,value1,value2) – заменяет в диапазоне

[begin,last) все значения value1 на значение value2. Например, команда

replace(note.begin(),note.end(),3,5) заменит в контейнере note все

значения 3 на значения 5.

replace_if(begin,end,pred,value) – заменяет в диапазоне

[begin,last) все значения, удовлетворяющие предикату pred, на значение

value2.

fill(begin,end,value) – заменяет все значения в диапазоне

[begin,last) на значение value.

copy(begin,end,result) – копирует элементы из диапазона

[begin,last) в диапазон [result,result+(end-begin)).

Пример 17. Пусть в список note1 введены значения 1 1 1 1 1, а в список note2

– значения 1 2 3 4 5 6 7 8 9 0. Дан код:#include <iostream>#include <list>#include <algorithm>#include "windows.h"using namespace std;void main(){ SetConsoleCP(1251); SetConsoleOutputCP(1251); int a; list <int> note1,note2; list <int>::iterator p; for (int i=1; i<=5; i++) {

cin>>a;note1.push_back(a);

} for (int i=1; i<=10; i++) {

cin>>a;note2.push_back(a);

} copy(note1.begin(),note1.end(),note2.begin()); for (p = note2.begin(); p != note2.end(); p++)

Page 43: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

43

{ cout<<*p<<" "; }cout<<"\n";}

Получим следующий результат:1 1 1 1 1 6 7 8 9 0

Мы рассмотрели часть алгоритмов, входящих в состав библиотеки STL. Если

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

справочнику по стандартной библиотеке С++.

Page 44: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

44

-Список литературыиинтернет ресурсов1. Мейерс С. «Эффективное использование STL. Библиотека

программиста» — СПб: Питер, 2002 —224 с.:ил.

2. Аммерааль Л. «STL для программистов на C++» Пер. с англ./ Леен

Аммерааль — М: ДМК, 1999 — 240 с.: ил.

3. Справочник по стандартной библиотеке C++ -

https://msdn.microsoft.com/ru-ru/library/cscc687y.aspx

4. C++ для начинающих - http://ci-plus-plus-snachala.ru/

5. Библиотека стандартных шаблонов STL - http :// cppstudio . com / cat /300/

Page 45: mmft.psu.rummft.psu.ru › docum › students › STL.docx · Web viewУчебное пособие предназначено для студентов 1 курса механико-математического

45

Оглавление

Аннотация..........................................................................................................................................................2

Введение............................................................................................................................................................2

1. Последовательные контейнеры. Итераторы. Предикаты.........................................................................4

1.1. Общие сведения о последовательных контейнерах. Понятие итератора. Общие методы работы с последовательными контейнерами............................................................................................................4

1.2. Контейнер vector..................................................................................................................................8

1.3. Контейнер deque................................................................................................................................13

1.4. Контейнер list. Предикаты................................................................................................................16

2. Адаптеры последовательных контейнеров...............................................................................................24

2.1. Понятие адаптера последовательного контейнера.............................................................................24

2.2. Контейнер stack.......................................................................................................................................24

2.3. Контейнер queue.....................................................................................................................................25

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

3.1. Понятие ассоциативного контейнера.....................................................................................................26

3.2. Контейнеры map и multimap..................................................................................................................27

3.3. Контейнеры set и multiset......................................................................................................................34

4. Алгоритмы...................................................................................................................................................37

4.1. Алгоритмы поиска и подсчета................................................................................................................37

4.2. Алгоритмы сортировки...........................................................................................................................39

4.3. Алгоритмы удаления и замены.............................................................................................................40

Список литературы и интернет-ресурсов......................................................................................................44

Оглавление......................................................................................................................................................45