1 STL — Standart Template Library Стандартная библиотека
1 STL - Standart Template Library Стандартная библиотека шаблонов Эта библиотека представляет большой набор данных структур и алгоритмов. STL разработана Александром Степановым и Менг Ли работающих в Hewlett-Packard Lab, им помогал Д. Л. Муссер из Ренсселэровского политехнического института. STL - это не просто расширение, он был принят комитетом по стантартизации ANSI/ISO в качестве составляющей стандартной библиотеки C++. STL поддерживает компилятор Borland, для которого его реализовала Rogue Wave Software Microsoft. У STL есть несколько версий. Мы с Вами посмотрим стандартную версию для VC++ Microsoft.
2 STL Главная идея STL Это уменьшение зависимости от стандартных библиотек С++. Главная беда стандартных библиотек очень тесная их связь с данными, что делает их очень неудобными для работы с типами данных пользователя. STL позволяет работать с любыми типами данных и производить над ними операции. Отличие STL она отделяет структуры данных от алгоритмов, которые с ними работают.
3 Создаем проект Win 32 Console // Stl1.cpp : Defines the entry point for the console application. #include "vector" #include "iostream.h" using namespace std; void main() { vector< int > MyArray; for (int x=0;x < 10;x++) MyArray.push_back(x); vector< int >::iterator i; for (i=MyArray.begin(); i!=MyArray.end();++i) cout << *i << endl; } Вместе с VC++ поставляются и все необходимые файлы для работы с STL при этом есть некоторые особенности: при объявлении vector не использовалось расширение *.h. Его можно не использовать, но кроме того его и нет. Данный файл идет без расширения.
4 Пространство имен Пространство имен namespace этот элемент языка мы обязаны принять его во внимание для работы с STL. Этот элемент создан для программ созданных из многих файлов, в которых есть опасность конфликта имен. Объявляется пространство имен командой namespace: C++ Спецификация namespace [идентификатор] { описание для этой рабочей области } Для использования рабочей области применяется команда using namespace: C++ Спецификация using namespace [идентификатор]
5 TestNameSpace // TestNameSpace.cpp // #include "stdafx.h" namespace spaceA //A { int MyVal=10; } namespace spaceB //B { int MyVal=20; } namespace spaceC //C { int MyVal=30; } void main() { }
6 TestNameSpace (продолжение) // TestNameSpace.cpp // #include "iostream.h" namespace spaceA { int MyVal=10; } namespace spaceB { int MyVal=20; } namespace spaceC { int MyVal=30; } void Test() { using namespace spaceB; cout << MyVal << " " << "spaceB" << endl; } void main() { using namespace spaceA; cout << MyVal << " " << "spaceA" << endl; Test(); cout << spaceC::MyVal << " " << "spaceC" << endl; }
7 Шаблоны функций основа STL Основу STL составляют шаблоны. Именно они позволяют значительно сократить количество кода для программирования алгоритмов. Рассмотрим задачу, смысл которой в одинаковых математических расчетах для разных типов. Представьте, что Вам нужно вычислять функцию: (x*x)-(2*x) Для типа int и double. Что делается классически ??? Пишутся две функции.
8 Пример : #include "iostream.h" int FInt(int x) { return (x*x)-(2*x); } double FDouble(double x) { return (x*x)-(2*x); } void main() { cout << "Int " << FInt(25) << endl; cout << "Double " << FDouble(3.12) << endl; } Если то же самое придется вычислять для других типов, то как Вы догадываетесь придется писать еще одну функцию. Выход из этой ситуации в применении шаблонов.
9 Применение шаблонов #include "iostream.h" template
10 Шаблоны классов Шаблоны классов очень сильно похожи на шаблоны функций и решают те же задачи. Они помогают производить одинаковые операции с разными типами данных. Пример перепишем на классы: #include "iostream.h" class CFInt { public: CFInt(int value) { x=value; } int GetValue() { return (x*x)-(2*x); } private: int x; }; class CFDouble { public: CFDouble(double value) { x=value; } double GetValue() { return (x*x)-(2*x); } private: double x; }; void main() { CFInt cI(25); CFDouble cD(3.12); cout << "CFInt " << cI.GetValue() << endl; cout << "CFDouble " << cD.GetValue() << endl; }
11 Теперь с шаблоном #include "iostream.h" template < class T > class Ftemp { public: Ftemp(T value) { x=value; } T GetValue() { return (x*x)-(2*x); } private: T x; }; void main() { Ftemp < int > cI(25); Ftemp < double > cD(3.12); cout << "cI " << cI.GetValue() << endl; cout << "cD " << cD.GetValue() << endl; } Обратите внимание на Ftemp< int > cI(25); именно здесь задается тип класса.
12 Компоненты STL В STL большое количество шаблонов, как классов так и функций. Мы можем их использовать с ООП или без него. В STL есть 3 основные компоненты. Итераторы Контейнеры Алгоритмы
13 1. Итераторы Итератор - это аналог указателя, с помощью них мы можем получать доступ к различных элементам данных. Можно использовать и пару итераторов для задания диапазона. Как и указатель для получения данных из итераторов их необходимо разыменовать с помощью операции: *. Всего есть пять классов итераторов. Входные Выходные Однонаправленные Двунаправленные Произвольного доступа
14 2. Контейнеры Контейнеры - это структуры данных такие как списки, очереди и так далее. Доступ к данным находящимся внутри контейнера осуществляется с помощью итераторов Основные контейнеры: vector - линейный массив list - двухсвязанный список set - ассоциативный массив уникальных ключей multiset - ассоциативный массив с возможность дублирования ключей map - ассоциативный массив с уникальными ключами и значениями multimap - ассоциативный массив с возможность дублирования ключей и значений stack - структура данных типа стек queue - структура данных типа очередь deque - очередь с двухсторонним доступом
15 3.Алгоритмы Алгоритмы - это шаблоны функций, с помощью которых производятся операции по работе с данными. Например сортировки или поиска.
16 Вектор Вектор (vector) напоминает нам массив, способен расти до произвольного размера, поддерживает информацию о размере. Как и массив к вектору можно обратить воспользовавшись операцией индексирования [ ]. Характеристики: Доступ к данных с одинаковой скоростью Вставка приводит к перемещению элементов При расширении данные копируются в другой блок Вектор оптимален для получения информации, но при большом количестве вставок лучше воспользоваться другими контейнерами, например, списками. Проблема в том, что физически вектор располагается в непрерывной памяти. На C это реализовывали функциями malloc.
17 Вектор Для работы с вектором необходимо подключить заголовочный файл: #include "vector" Объявить рабочую область: using namespace std; После этого вектор необходимо объявить, это можно сделать двумя способами. vector< int > vArray1; - указывается пустой вектор vector< int > vArray2(30); - указывается начальный размер Можно получать информацию о параметрах вектора: size() - сколько данных храниться capacity() - сколько может храниться до изменения размера max_size() - максимальный размер обычно равен наиболее большому доступному блоку памяти
18 Пример // TestVector.cpp. #include "vector" #include "iostream.h" using namespace std; void main() { vector
19 Инициализация вектора В дополнение можно сказать, что вектор можно инициализировать с заранее установленными значениями. Пример демонстрирующий и доступ к данным вектора через операцию индексирования - [ ]. vector vVec(5,10); for (int x=0;x < 5;x++) cout << vVec[x] << endl;
20 Функции вектора assign - заполнить часть вектора необходимыми данными. В данном примере первые три элемента заполняются цифрой два: vVec.assign(3,2); for (x=0;x < 5;x++) cout << vVec[x] << endl; Получить первый и последний элемент вектора, для этого есть функции front() и back(). vVec.assign(5,1); vVec[0]=0; vVec[4]=4; cout << vVec.front() << " " << vVec.back() << endl;
21 Функции вектора Вставку элемента с перемещением можно сделать функцией insert. Вставка производится в первую позицию с перемещением элементов вниз. for (x=0;x < 5;x++) cout << vVec[x] << " "; cout << endl; vVec.insert(vVec.begin(),25); for (x=0;x < 6;x++) cout << vVec[x] << " "; cout << endl; Можно поместить число в конец вектора воспользовавшись функцией push_back(): vVec.push_back(99); for (x=0;x < 7;x++) cout << vVec[x] << " "; cout << endl;
22 Функции вектора Можно удалить последний элемент с сокращением размера: vVec.pop_back(); for (x=0;x < vVec.size();x++) cout << vVec[x] << " "; cout << endl; Для удаления используется функция erase(): vVec.erase(vVec.begin()+2,vVec.begin()+4 ); for (x=0;x < vVec.size();x++) cout << vVec[x] << " "; cout << endl; Изменяет размер вектора функция resize(): vVec.resize(3); for (x=0;x < vVec.size();x++) cout << vVec[x] << " "; cout << endl;
23 Применение алгоритмов к вектору Одним из алгоритмов является сортировка, вот мы и посмотрим как она работает с вектором. Для сортировки можно применить стандартный алгоритм sort. Для его использования необходимо подключить файл заголовков алгоритмов. #include "algorithm" После чего можно сортировать, как весь вектор, так и отдельные его части, что очень приятно.
24 Пример vector< int > v1(10); vector< int > v2(10); for (int x=0;x < v1.capacity() ;x++) v1[x]=10-x; for (x=0;x < v1.capacity() ;x++) v2[x]=10-x; for (x=0;x < v1.size();x++) cout << v1[x] << " "; cout << endl; for (x=0;x < v2.size();x++) cout << v2[x] << " "; cout << endl; cout << "___________ SORT _____________" << endl; sort(v1.begin(),v1.end()); for (x=0;x < v1.size();x++) cout << v1[x] << " "; cout << endl; sort(v2.begin()+1,v2.end()-1); for (x=0;x < v2.size();x++) cout << v2[x] << " "; cout << endl; здесь показано, что можно векторы сортировать и с ними работают стандартные алгоритмы.
25 Наш класс в векторе На данный момент мы использовали в векторе стандартные классы, а как быть для того, чтобы в вектор можно было поместить произвольный класс ? Для этого нужно соблюдать ряд условий. Минимальные условия. Конструктор по умолчанию Конструктор копий Деструктор
26 Пример // СlassVec.cpp // #include "vector" #include "iostream.h" using namespace std; class CMyClass { public: CMyClass(); // конструктор по умолчанию CMyClass(const CMyClass &my); // конструктор копий CMyClass(int xx,int yy); ~CMyClass(); // деструктор int x; int y; }; CMyClass::CMyClass() // конструктор по умолчанию { x=0; y=0; } CMyClass::CMyClass(const CMyClass &my) // конструктор копий { x=my.x; y=my.y; }
27 Пример (продолжение) CMyClass::CMyClass(int xx,int yy) { x=xx; y=yy; } CMyClass::~CMyClass() // деструктор { } void main() { vector< CMyClass > v; v.push_back(CMyClass(1,1)); v.push_back(CMyClass(2,2)); v.push_back(CMyClass(3,3)); for (int x=0;x < v.size();x++) cout << v[x].x << " " << v[x].y << endl; }; Это только самые базовые возможности. Для полного функционирования потребуется перегрузить достаточное количество операций. Довольно много. Как определить необходимость перегрузки данной операции ? Компилятор сам скажет : в виде error. Мы знаем, что вектор может работать с архивом, а наш класс пока не умеет, и сортировка вряд ли будет нормальная пока не определены правила, как определить кто старше или больше !!!
28 Списки Для использования списков необходимо подключить заголовочный файл и выбрать область. #include "list" using namespace std; Теперь список можно объявлять. list< int > intList;// пустой список способный хранить числа list< int > intListTest(3);// в списке 3 элемента list< int > intListInit(3,1); //еще и инициализируем этот список числом 1
29 Списки Количество элементов определяем функцией size(): cout << intListInit.size() << endl; Можно проверить список на пустоту. if (intList.empty()) cout << " int List empty " << endl; Для вставки можно использовать три метода Insert(), push_back(), push_front().
30 Пример // testList.cpp #include "iostream" #include "list" using namespace std; list< int > intList; list< int > intListTest(3); list< int > intListInit(3,1); void ViewintListInit(); void main() { cout << intListInit.size() << endl; if (intList.empty()) cout << " int List empty " << endl; ViewintListInit(); intListInit.push_back(100); intListInit.push_front(0); intListInit.insert(intListInit.begin(),55); ViewintListInit(); } void ViewintListInit() { copy(intListInit.begin(),intListInit.end(), ostream_iterator< int >(cout," ")); cout << endl; }
31 Из списка можно удалять элементы равные определенному значению. intListInit.remove(1); ViewintListInit(); Очень многие возможности векторов списков и так далее реализуются через итераторы. Например, чтобы удалить произвольный элемент списка нужен итератор.
32 Вы должны воспринимать итератор на данный момент, как указатель C++. В общем случае это одно и тоже. Давайте посмотрим как применить алгоритм find к массиву C. Массив это и есть набор указателей.
33 Пример // TestIter.cpp #include "iostream.h" #include "algorithm" using namespace std; #define ARRAY_SIZE 10 int Arr[ARRAY_SIZE]; void main() { for (int x=0;x < ARRAY_SIZE;x++) Arr[x]=x; int* rezult=find(Arr,Arr+ARRAY_SIZE,3); if (rezult==Arr+ARRAY_SIZE) cout << "Not Found 3 " << endl; else cout << "Yes 3" << endl; } В функции find два указателя. Указатель начала массива указатель конца массива. Это и есть как их называют - итераторы. При нахождении вам вернется итератор значения, чтобы проверить, что ничего нет мы проверяем с итератором за концом массива.
34 Функции begin() и end() Вы уже видели, как используются подобные функции типа begin() и end() для получения начала и конца итераторов. Главный вопрос почему не пользоваться указателями ??? Не получится. Представим массив из структур. struct A { int x; int y; char buffer[100]; }; В С[100]; Так вот для того, чтобы работать с указателями вы должны делать примерно так. A* D; D=D+sizeof(A); Только так вы можете идти от одной структуры к другой.
35 Итераторы Вывод: ЭТО МОЖНО ТОЛЬКО ЕСЛИ СТРУКТУРЫ РАСПОЛОЖЕНЫ ЛИНЕЙНО, то есть одна за другой. Тут же мы получим ограничение на то, что блок памяти должен быть непрерывный. Это очень неудобно и ограничивает размер при наличии памяти. Выход только один ЗАВЕСТИ ОТДЕЛЬНЫЙ МАССИВ С ИТЕРАТОРАМИ (указателями). В нем будут линейно храниться указатели на элементы. Ну и что скажете Вы ? Все равно нужен линейный блок памяти. Нужен, но только структуры могут быть по размеру очень большими. Даже в примере на место данной структуры можно поместить массу указателей. И теперь размер ограничивается непрерывной памятью для указателей. Это намного больше, кроме того сами структуры могут быть рассортированы по всей памяти. Итак, давайте попробуем сформулировать, что такое итератор на данной степени понимания: Это массив указателей на элементы структур.
7706-stl_lekciya1_2013.ppt
- Количество слайдов: 35