Вы находитесь на странице: 1из 29

Составные типы данных

Прикладное программирование
кафедра
прикладной и компьютерной оптики
2

Составные типы данных


Гомогенные Гетерогенные

для хранения однотипных для хранения неоднородных


Назначение
переменных разнотипных переменных

массив, строка,
структура, класс
Пример список, стек, очередь,
набор, карта, дерево
3

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


имеющих один и тот же тип
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'};
4

Динамическое размещение
массива
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]

См. пример программы


5

Передача массива в функцию


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

// указатель на массив + количество элементов в массиве


double sum(double* m, int n) // или double m[]
{
double s=0.;
for(int i=0; i<n; ++i)
{
s+=m[i];
}
return s;
}
См. пример программы
6

Двумерный массив
Для создания двумерного массива необходимо указать в квадратных
скобках два значения – количество строк и столбцов в массиве
double matrix[3][2]; // двумерный массив 2х3

double sum=0.;
for(int i=0; i<3; i++) // номер строки
{
for(int j=0; j<2; j++) // номер столбца
{
sum+=matrix[i][j];
[0][0] [0][1]
}
} [1][0] [1][1]
[2][0] [2][1]
matrix[0][0];

matrix[2][1]; [0][0] [0][1] [1][0] [1][1] [2][0] [2][1]


7

Динамическое размещение
двумерного массива
Двумерный массив можно разместить динамически, только если
представить его как одномерный
◼ вместо доступа по индексам [i][j], придется вычислять индекс одномерного
массива, которому будет соответствовать необходимый элемент двумерного
массива
• Например, элементу [1][0] двумерного массива будет соответствовать индекс [2] одномерного
массива

// указатель на двумерный массив matrix[3][2]


double *matrix=new double[3*2];

// matrix[i][j]
matrix[i*2+j]=0.;
0 1 2 3 4 5

[0][0] [0][1] [1][0] [1][1] [2][0] [2][1]


// например matrix[1][0]
matrix[1*2+0]=0.;

delete [] matrix; //освободить память


См. пример программы
8

Контейнеры
Контейнер – тип данных, предназначенный для хранения
однотипных данных
◼ вектор, стек, очередь, список, ассоциативный массив, дерево

Хранение элементов контейнера


◼ последовательно (непрерывным блоком)
◼ разбросаны по всей памяти

Доступ к элементам контейнера


◼ по индексу
◼ только последовательным перебором
9

STL (Standard Template Library) –


стандартная библиотека шаблонов
Контейнеры
◼ объекты для хранения однотипных данных:
• последовательные (vector, deque, list);
• ассоциативные (set, multiset, map, multimap);
Адапторы
◼ объекты, созданные на основе базовых контейнеров, с измененным
интерфейсом (например, queue, stack)
Итераторы
◼ объекты, которые используются для универсального доступа к элементам
хранящимся в контейнере любого типа
Алгоритмы
◼ обобщенные процедуры для обработки элементов любых контейнеров
Функции-объекты
◼ объекты, у которых перегружен оператор вызова функций
10

Контейнеры:
вектор, стек, очередь
Вектор
◼ хранение элементов единым блоком
◼ доступ к любому элементу по индексу

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

Очередь
◼ хранение элементов единым блоком
◼ доступ только к первому элементу,
внесенному в очередь
11

Контейнеры: список, дерево,


ассоциативный массив
Список
◼ элементы разбросаны по памяти
• каждый элемент содержит указатель на
последующий и предыдущий
◼ только перебор

Дерево
◼ элементы разбросаны по памяти
◼ обхода дерева от корня
• родитель содержит ссылки на дочерние
элементы

Ассоциативный массив
◼ элементы разбросаны по памяти
◼ обход дерева по ключу
12

Вектор
Вектор - одномерный массив проиндексированных элементов
• Доступ к функциям вектора производится через оператор "."
• Подробнее о классах и шаблонах см. главу 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]; //доступ по индексу
}
13

Функции работы с вектором


Размер (количество элементов) контейнера
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 См. пример программы


14

Список
Список – структура данных для организации хранения
элементов с эффективной вставкой и удаления в любом
месте этой структуры, не требует доступа по индексу
◼ УЗЕЛ (Node) – объект, который содержит ссылки на последующий и
предыдущий элементы, а также значение данного элемента списка

Простой односвязный список

Простой двухсвязный список

Кольцевой двухсвязный список


15

Функции списка
STL – простой двухсвязный список

list<int> example;

example.push_back(0); // вставка в конец


example.push_front(1); // вставка в начало
x.insert(x.begin(), 3); // вставка в любое место списка

◼ (переразмещения данных в памяти не происходит)


16

Итераторы
Итератор – это обобщённый "указатель" на элемент,
хранящийся в контейнере
list<double> ls;
list<double>::iterator it;

◼ оператор * – разыменование и получение доступа к значению элемента


(*it)=5;

◼ операторы «++» и «– –» получение указателя на следующий и


предыдущий элемент
it++, it--

◼ итератор на первый элемент контейнера


it=ls.begin()

◼ итератор на следующий после последнего элемент контейнера


it=ls.end()
17

Использование итераторов
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++;
}
См. пример программы
18

Двусторонняя очередь (deque)


Двусторонняя очередь – последовательность, которая:
◼ поддерживает произвольный доступ к элементам (аналогично vector)
◼ поддерживает вставку и удаление в начало последовательности
◼ Кроме того:
• не имеет функций-членов capacity() и reserve()
• не предоставляет никаких гарантий на допустимость итератора

См. пример программы


19

Стек (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
См. пример программы
20

Очередь (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
21

Ассоциативный массив
Ассоциативный массив - используется для хранения
связанных пар "ключ-значение" ("key-value")
◼ массив, в котором индекс может быть не целочисленного типа
◼ организуются как сбалансированное дерево узлов
pair<const key, mapped_type>

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


◼ map – ассоциативный массив, по ключу в контейнере хранится одно
значение
◼ multimap – ассоциативный массив с повторяющимися ключами
◼ set – массив уникальных ключей без значений
◼ multiset – массив с повторяющимися ключами без значений
22

Ассоциативный массив 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;
}
См. пример программы
23

Ассоциативный массив 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;
}

См. пример программы


24

Алгоритмы
Алгоритмы – обобщенные процедуры для обработки
элементов любых контейнеров
#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);
25

Алгоритмы не модифицирующие
контейнер
Алгоритмы не модифицирующие контейнер – процедуры
поиска и сравнения

list<string> ls;

list<string>::const_iterator it;
// поиск значения "К8" в диапазоне от ls.begin() до ls.end()
it=find(ls.begin(), ls.end(), "К8");
26

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

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);
27

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

vector<int> v(100);

// сортировка массива
sort(v.begin(), v.end());
// перестановка элементов массива в обратном порядке
reverse(v.begin(), v.end());
28

Функции-помощники
Функции-помощники (перестановки и сравнения)

vector<int> v(100);
vector<int>::iterator it=v.begin();

it++;
swap(*v.begin(), *it);
29

Численные алгоритмы
#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, ...)

См. пример программы