300 likes | 581 Views
Составные типы данных. Составные типы данных. Массивы. Массив - это группа последовательных ячеек памяти, имеющих один и тот же тип int data[4]; Нумерация элементов – от 0 до < размер-1 > data[0]=1; data[1]=2; data[2]=3; data[3]=4; Объявление и инициализация
E N D
Массивы • Массив - это группа последовательных ячеек памяти, имеющих один и тот же тип • int data[4]; • Нумерация элементов – от 0 до <размер-1> • data[0]=1; • data[1]=2; • data[2]=3; • data[3]=4; • Объявление и инициализация • double v[3]={0.3, 2.2, 2.}; • char symbols[]={'a', 'b', 'c', 'd', 'e'};
Динамическое размещение массива • double *data; // указатель на массив • data=new double[1000]; // указатель на 0-й элемент массива • // инициализация • for(int i=0; i<1000; i++) • { • data[i]=0.; • } • delete [] data; // обязательно освободить память • data+1; // указатель на 1-й элемент • data+100; // указатель на 100-й элемент, • *(data+4); // эквивалентно data[4] См. пример программы
Передача массива в функцию • Передача массива в функцию может осуществляться только по указателю на нулевой элемент, с дополнительной информацией о количестве элементов в массиве • // указатель на массив + количество элементов в массиве • double sum(double* m, int n) // или double m[] • { • double s=0.; • for(int i=0; i<n; ++i) • { • s+=m[i]; • } • return s; • } См. пример программы
Двумерный массив • Для создания двумерного массива необходимо указать в квадратных скобках два значения – количество строк и столбцов в массиве • doublematrix[3][2]; // двумерный массив 2х3 • double sum=0.; • for(inti=0; i<3; i++)// номер строки • { • for(intj=0; j<2; j++) // номер столбца • { • sum+=matrix[i][j]; • } • } • matrix[0][0]; • matrix[2][1];
Динамическое размещение двумерного массива • Двумерный массив можно разместить динамически, только если представить его как одномерный • вместо доступа по индексам [i][j], придется вычислять индекс одномерного массива, которому будет соответствовать необходимый элемент двумерного массива • Например, элементу [1][0] двумерного массива будет соответствовать индекс [2] одномерного массива • // указатель на двумерный массив matrix[3][2] • double *matrix=new double[3*2]; • // matrix[i][j] • matrix[i*2+j]=0.; • // например matrix[1][0] • matrix[1*2+0]=0.; • delete [] matrix; //освободить память См. пример программы
Контейнеры • Контейнер – тип данных, предназначенный для хранения однотипных данных • вектор, стек, очередь, список, ассоциативный массив, дерево • Хранение элементов контейнера • последовательно (непрерывным блоком) • разбросаны по всей памяти • Доступ к элементам контейнера • по индексу • только последовательным перебором
STL (Standard Template Library) – стандартная библиотека шаблонов • Контейнеры • объекты для хранения однотипных данных: • последовательные (vector, deque, list); • ассоциативные (set, multiset, map, multimap); • Адапторы • объекты, созданные на основе базовых контейнеров, с измененным интерфейсом (например, queue, stack) • Итераторы • объекты, которые используются для универсального доступа к элементам хранящимся в контейнере любого типа • Алгоритмы • обобщенные процедуры для обработки элементов любых контейнеров • Функции-объекты • объекты, у которых перегружен оператор вызова функций
Контейнеры: вектор, стек, очередь • Вектор • хранение элементов единым блоком • доступ к любому элементу по индексу • Стек • хранение элементов единым блоком • доступ только к последнему элементу, внесенному в стек • Очередь • хранение элементов единым блоком • доступ только к первому элементу, внесенному в очередь
Контейнеры: список, дерево, ассоциативный массив • Список • элементы разбросаны по памяти • каждый элемент содержит указатель на последующий и предыдущий • только перебор • Дерево • элементы разбросаны по памяти • обхода дерева от корня • родитель содержит ссылки на дочерние элементы • Ассоциативный массив • элементы разбросаны по памяти • обход дерева по ключу
Вектор • Вектор - одномерный массив проиндексированных элементов • Доступ к функциям вектора производится через оператор "." • Подробнее о классах и шаблонах см. главу 4 и раздел 5.4. • #include <vector> • using namespace std; • vector<double> x;// создание вектора • x.resize(10);// изменение размера вектора • x.resize(x.size()+100); // изменение размера вектора • double sum=0.0; • for(int i=0; i<x.size(); i++) • { • sum+=x[i]; //доступ по индексу • }
Функции работы с вектором • Размер (количество элементов) контейнера • int n=x.size(); • Изменение размера контейнера • x.resize(100); • Доступ к элементам контейнера • x[i]=5; • Добавить элемент в конец контейнера • Добавляет копию элемента • x.push_back(7); • Определяет пустойли контейнер • bool res=x.empty(); // эквивалентно x.size() == 0 • Очистить контейнер • разрушает все элементы и освобождает контейнер • x.clear(); • Выделение дополнительной памяти для размещения новых эл-в • x.reserve(200); • Определяет кол-во элементов, для которых зарезервирована.память • int n=x.capacity(); • Остальные функции – см.Приложение 5 См. пример программы
Список • Список – структура данных для организации хранения элементов с эффективной вставкой и удаления в любом месте этой структуры, не требует доступа по индексу • УЗЕЛ (Node) – объект, который содержит ссылки на последующий и предыдущий элементы, а также значение данного элемента списка • Простой односвязный список • Простой двухсвязный список • Кольцевой двухсвязный список
Функции списка • STL – простойдвухсвязный список • list<int> example; • example.push_back(0); // вставка в конец • example.push_front(1); // вставка в начало • x.insert(x.begin(), 3); // вставка в любое место списка • (переразмещения данных в памяти не происходит)
Итераторы • Итератор – это обобщённый "указатель" на элемент, хранящийся в контейнере • list<double> ls; • list<double>::iterator it; • оператор * – разыменование и получение доступа к значению элемента • (*it)=5; • операторы «++» и «––» получение указателя на следующий и предыдущий элемент • it++, it-- • итератор на первый элемент контейнера • it=ls.begin() • итератор на следующий после последнего элемент контейнера • it=ls.end()
Использование итераторов • list<double> x; • list<double>::iterator it; • for(it=x.begin(); it!=x.end(); it++) • { • sum+=(*it); //доступ к элементам по итератору • } • it=x.begin(); • while(it!=x.end()) • { • sum+=*it; • it++; • } См. пример программы
Двусторонняя очередь (deque) • Двусторонняя очередь – последовательность, которая: • поддерживает произвольный доступ к элементам (аналогично vector) • поддерживает вставку и удаление в начало последовательности • Кроме того: • не имеет функций-членов capacity() и reserve() • не предоставляет никаких гарантий на допустимость итератора См. пример программы
Стек (stack) • Стек – адаптер очереди, который организует ее работу по правилу "last in, first out" (LIFO) • не предоставляет функций для получения итераторов и их перебора • позволяет проверить, какой элемент находится на вершине стека (top) • stack<int> s; • s.push(8); // s = 8 • s.push(7);// s = 7 8 • s.push(4);// s = 4 7 8 • cout<<s.top()<<endl; // 4 • s.pop(); • cout<<s.top()<<endl; // 7 • s.pop(); • cout<<s.top()<<endl; // 8 См. пример программы
Очередь (queue) • Очередь – это адаптер очереди, который организует ее работу по правилу "first in, first out" (FIFO) • не предоставляет функций для получения итераторов и их перебора • позволяет проверить, какой элемент находится на вершине стека (front) • queue<int> q; • q.push(8); // q = 8 • q.push(7);// q = 7 8 • q.push(4);// q = 4 7 8 • cout<<q.front()<<endl; // 8 • q.pop(); • cout<<q.front()<<endl; // 7 • q.pop(); • cout<<q.front()<<endl; // 4
Ассоциативный массив • Ассоциативный массив - используется для хранения связанных пар "ключ-значение" ("key-value") • массив, в котором индекс может быть не целочисленного типа • организуются как сбалансированное дерево узлов • pair<const key, mapped_type> • Ассоциативные контейнеры STL • map – ассоциативный массив, по ключу в контейнере хранится одно значение • multimap – ассоциативный массив с повторяющимися ключами • set – массив уникальных ключей без значений • multiset – массив с повторяющимися ключами без значений
Ассоциативный массив map • Доступ к элементам по ключу • map<string, double> glass; • double n=glass["K8"]; • поиск по ключу • если ключ не найден, то вставляется элемент со значением по умолчанию (0) • glass["K8"]=1.5; • поиск по ключу • если ключ не найден, то вставляется элемент с заданным значением • Доступ к элементам по итератору (объект pair) • первый элемент (pair::first) – ключ • второй элемент (pair::second) – значение • элементы хранятся в отсортированном виде: от меньшего ключа к большему ключу • map<string, double>::iterator it; • for(it=glass.begin(); it!=glass.end(); it++) • { • cout<<it->first<<""<<it->second<<endl; • } См. пример программы
Ассоциативный массив set • Доступ к элементам по итератору • все значения уникальны и отсортированы • от меньшего ключа к большему ключу • set<string> glass; • map<string>::iterator it; • glass.insert("K8"); • glass.insert("ТK14"); • glass.insert("K8"); • for(it=glass.begin(); it!=glass.end(); it++) • { • cout<<*it<<""<<endl; • } См. пример программы
Алгоритмы • Алгоритмы – обобщенные процедуры для обработки элементов любых контейнеров • #include <algorithm> • using namespace std; • list<double> x; • // вычисление суммы через итераторы • list<double>::iterator it; • for(it=x.begin(); it!=x.end(); it++) • { • sum+=(*it); • } • // вычисление суммы через алгоритмы • sum=accumulate(x.begin(), x.end(), 0.0);
Алгоритмы не модифицирующие контейнер • Алгоритмы не модифицирующие контейнер – процедуры поиска и сравнения • list<string> ls; • list<string>::const_iterator it; • // поиск значения "К8" в диапазоне от ls.begin() до ls.end() • it=find(ls.begin(), ls.end(), "К8");
Алгоритмы модифицирующие значение элементов контейнера • Алгоритмы модифицирующие значение элементов контейнера, но неизменяющие порядок их следования – выполнение действий над каждым элементом контейнера, поиск и замена • vector<int> v(100); • // заполнение всех элементов от ls.begin() до ls.end() • // значением 0 • fill(v.begin(), v.end(), 0); • // замена всех элементов от ls.begin() до ls.end(), • // равных -1 на 1 • replace(v.begin(), v.end(), -1, 1);
Алгоритмы модифицирующие контейнер • Алгоритмы модифицирующие контейнер – функции копирования, перестановок, удаления, тасования и сортировки, разбиения и слияния последовательностей • vector<int> v(100); • // сортировка массива • sort(v.begin(), v.end()); • // перестановка элементов массива в обратном порядке • reverse(v.begin(), v.end());
Функции-помощники • Функции-помощники (перестановки и сравнения) • vector<int> v(100); • vector<int>::iteratorit=v.begin(); • it++; • swap(*v.begin(), *it);
Численные алгоритмы #include <numeric> • accumulate - накапливает результаты выполнения операций над последовательностью • (сложение элементов) • inner_product - накапливает результаты выполнения операций над двумя последовательностями • (перемножениеэлементов) • partial_sum - позволяет получить последовательность инкрементных изменений • (a, a+b, a+b+c, a+b+c+d, ...) • adjacent_difference - позволяет получить последовательность декрементных изменений • (a, b-a, c-b-a, d-c-b-a, ...) См. пример программы