Лекции / Лекция_8_Структуры_данных_ipynb_Colab (1)
.pdf
Структуры данных
Структура данных — частный случай абстрактного типа данных. Описывает программные компоненты предназначенные для хранения и обработки данных.
Абстрактный тип данных — математическая модель для типов данных. Тип данных определяется возможными значениями, возможными операциями над данными этого типа и поведения этих операций. Абстрактный тип данных определяет набор функций, независимых от конкретной реализации типа, для оперирования его значениями.
Структуры данных определяют набор операций для хранения и обработки данных. Этот набор операций довольно часто описывают в виде интерфейсов, которые скрывают соответствующие реализации типов. Программисты работают с абстрактными типами данных исключительно через их интерфейсы, поскольку реализация может в будущем измениться. Данные которые хранятся в структурах данных называют элементами этой структуры.
Классификация структур данных
Статические структуры — структурированное множество значений типа. Статические структуры отличаются отсутствием изменчивости, память для них выделяется один раз и ее объем остается неизменным до уничтожения структуры.
Динамические структуры — множество значений типа. Характеризуются отсутствием физической смежности элементов структуры в памяти, непостоянством и непредсказуемостью размера (числа элементов) структуры в процессе ее обработки.
Массив
Массив — конечная упорядоченная последовательность элементов. Доступ к каждому из них возможен по индексу (индексам) в роли которых выступают целые числа. Массивы относят к статическим структурам данных.
Поддерживаемые операции:
Получение элемента по его индексу Изменение значения элемента по его индексу
Список
Список — это абстрактный тип данных, представляющий собой упорядоченный набор значений, в котором некоторое значение может встречаться более одного раза. Можно считать список компьютерной реализацией математического понятия конечной последовательности.
Список — динамическая структура данных.
Поддерживаемые операции:
Добавление элемента в список Удаление элемента из списка Получение элемента Замена элемента
Получение размера списка
Стек
Стек — это абстрактный тип данных, представляющий собой список элементов, организованных по принципу LIFO (англ. last in — first out, «последним пришёл — первым вышел»). Стек является динамической структурой данных.
Поддерживаемые операции:
Добавление элемента в вершину стека Удаление элемента из вершины стека
Получение элемента с вершины стека без удаления Получение размера стека
Очередь
Очередь — это абстрактный тип данных, представляющий собой список элементов, организованных по принципу FIFO (англ. first in — first out, «первым пришёл — первым вышел»).
Очередь является динамической структурой данных.
Поддерживаемые операции:
Добавление элемента в конец очереди Удаление элемента из головы очереди Получение головного элемента без удаления Получение размера очереди
Ассоциативный массив
Ассоциативный массив — абстрактный тип данных, позволяющий хранить пары вида «(ключ, значение)». Предполагается, что
ассоциативный массив не может хранить две пары с одинаковыми ключами.
Поддерживаемые операции:
Добавление пары
Удаление пары Поиск пары и поиск значения по ключу
Получение размера ассоциативного массива
Дерево
Дерево — абстрактный тип данных, позволяющий хранить данные в виде набора связанных узлов. Дерево — динамическая структура данных.
Поддерживаемые операции:
вставка нового элемента в определённую позицию вставка поддерева добавление ветви дерева
нахождение корневого элемента для любого узла нахождение наименьшего общего предка двух вершин перебор всех элементов дерева перебор элементов ветви дерева поиск изоморфного поддерева поиск элемента удаление ветви дерева удаление поддерева удаление элемента
Граф
Граф — абстрактный тип данных, позволяющий хранить данные в виде набора вершин и связей между этими вершинами
(ребрами). Граф — динамическая структура данных.
Поддерживаемые операции:
добавление новой вершины удаление вершины добавление ребра удаление ребра проверка на смежность
получение соседних вершин получить значение вершины установить значение вершины
Массив
Массив — структура данных, хранящая набор значений (элементы массива), идентифицируемых по индексу или набору индексов. В качестве индексов используются целые числа из определенного диапазона. Особенностью массива является константная сложность получения элемента массива по индексу.
Набор операций, предоставляемых массивом:
Получение значения по индексу Установка значения по индексу
Размер массива — количество элементов в нем.
Размерность массива — минимальное количество индексов, необходимое для однозначной адресации элемента массива.
Форма или структура массива — сведения о количестве размерностей и размере массива по каждой из размерностей. Может
быть представлена одномерным массивом.
Гомогенные и гетерогенные массивы
Гомогенные массивы — массивы, хранящие значения одного типа.
Гетерогенным называется массив, в разные элементы которого могут быть непосредственно записаны значения, относящиеся к
различным типам данных. Массив, хранящий указатели на значения различных типов, не является гетерогенным, так как
собственно хранящиеся в массиве данные относятся к единственному типу — типу «указатель».
Статические и динамические массивы
Статические массивы — массивы, размер которых остается постоянным всё время существования массива.
Динамические массивы — массивы, размер которых может быть изменён во время существования массива. Наиболее частая реализация заключается в создании статического массива, и если в нём уже нет места под новый элемент, то создание нового статического массива большего размера, копирование данных из первого и удаление первого массива.
Массивы переменной длины — массивы, размер которых не известен на момент компиляции. Размер такого массива можно указать с помощью значения переменной или математическим выражением. Массивы переменной длины обычно к динамическим массивам не относят.
Реализация в Python
Поддержка массивов в Python на уровне стандартной библиотеки реализована только для небольшого списка типов данных. Это символ, целое число и вещественное число. Для остальных типов массивы не поддерживаются и нужно использовать списки или сторонние пакеты расширения (NumPy и т. д.). Для работы требуется импортировать модуль array . Поддерживается создание массива на основе строки, списка (целые и вещественные числа) и последовательности байт. При создании нужно указать тип данных, хранимых в массиве. Массивы гомогенные, динамические. Индексация начинается с нуля.
Таблица соответствий типов данных массива
Код типа |
Тип в языке C |
Тип в Python |
Размер в байтах |
b |
signed char |
int |
1 |
B |
unsigned char |
int |
1 |
u |
wchar_t |
Unicode character |
2 |
h |
signed short |
int |
2 |
H |
unsigned short |
int |
2 |
i |
signed int |
int |
2 |
l |
unsigned int |
int |
2 |
I |
signed long |
int |
4 |
L |
unsigned long |
int |
4 |
q |
signed long long |
int |
8 |
Q |
unsigned long long |
int |
8 |
f |
float |
float |
4 |
d |
double |
float |
8 |
Методы поддерживаемые массивами для добавления, вставки и удаления элементов
Структура данных |
|
Метод для создания массива на ее основе |
append(x) |
|
Вставка элемента в конец |
insert(i, x) |
|
Вставка элемента на i индекс |
pop([i]) |
Удаление с получением элемента по индексу. Если индекс не указан то последний элемент. |
|
remove(x) |
|
Удаление элемента из массива |
reverse() |
|
Реверс массива |
#ПримериспользованмассивовяPython |
||
import array |
|
|
arr=array.array( |
'l',[ 0, -2, 5]) |
|
arr.append(6) |
|
|
print(arr) |
|
|
s= 0
for i in range(len(arr)): s+=arr[i]
print(s)
array('l', [0, -2, 5, 6]) 9
Список
Список — это абстрактный тип данных, представляющий собой упорядоченный набор значений, в котором некоторое значение может встречаться более одного раза. Список — динамическая структура данных.
Поддерживаемые операции:
Добавление элемента в список
Удаление элемента из списка Получение элемента по индексу
Замена элемента по индексу Получение размера списка
В качестве основы списка можно использовать массивы переменной длинны. В таком случае получение и замена элемента массива по индексу реализуется особенно просто. Сложности возникнут только со вставкой и удалением элемента из списка. Особое внимание следует уделить вопросам увеличения и уменьшения размера списка на основе массива.
Реализации списка на основе массива
В качестве основы списка берем массив нужного типа данных. Его размер будем называть capacity (емкость). Также введем дополнительную переменную size (размер), она будет указателем на место для добавления элемента и к тому же используется для получения количества добавленных элементов. При создании списка устанавливается в начало массива.
Добавление значения в конец списка
Если size меньше чем capacity, то добавляем элемент на индекс size и увеличиваем size на единицу.
Добавление значения в конец списка
Если size равно capacity, то создаем новый массив размером (capacity * 3) / 2 + 1 . Копируем данные из базового массива в новый. Указываем, что теперь для хранения используется новый массив. Добавляем элемент на индекс size и увеличиваем size на единицу.
Вставка значения по индексу
Проверяем достаточно ли места для вставки. Если нет, запускаем процесс увеличения размера. Сдвигаем правую часть массива (от индекса на который вставляем элемент до size) на одну позицию вправо (желательно вызвать быструю функцию копирования массива блоками).
Ставим элемент на нужный индекс. Увеличиваем size на единицу.
Удаление элемента по индексу
Сдвигаем правую часть массива (от индекса удаляемого элемента до size) на одну позицию влево (желательно вызвать быструю функцию копирования массива блоками).
Уменьшаем значение size на единицу
Получение и замена элемента по индексу
При получении значения по индексу сначала проверяют корректность индекса. После чего возвращаем значение по индексу.
При замене значения по индексу сначала проверяют корректность индекса. После чего заменяем значение по индексу.
Уменьшение размера списка
В большинстве случаев список только увеличивает свою емкость. Автоматического уменьшения емкости не предусматривают. Для уменьшения емкости используют функцию, вызов которой осуществляется по желанию разработчика. В этой функции обычно
устанавливают capacity равное size .
Создают новый массив размером size . Копируют данные из основного массива в новый. Указываем что новый массив теперь используется вместо основного.
Получение размера списка
Для получения размера списка достаточно вернуть значение size.
Оценка сложности операций
Операция |
Сложность операции в худшем случае |
Вставка элемента
Удаление элемента
Получение по индексу
Изменение по индексу
Получение размера
Так как в Python отсутствует поддержка массивов, то реализация списка становится бессмысленной.
Односвязный список
Связанный список
Связанный список — базовая динамическая структура данных (одна из возможных реализаций списка), состоящая из узлов, каждый из которых содержит как собственно данные, так и одну или две ссылки (указатели) на следующий и/или предыдущий узел списка.
Линейный односвязный список (односвязный список) — разновидность связанного списка. Узел содержит данные и одну ссылку (указатель) на следующий элемент списка. Довольно часто используется также альтернативное определение: односвязный список — рекурсивная линейная структура данных, которая либо пуста, либо ссылается на узел (который хранит данные и ссылку на следующий узел).
Преимущества и недостатки связанных списков
Как уже было сказано выше, связанные списки — это динамическая структура данных. По сравнению с массивами они обладают рядом как преимуществ, так и недостатков.
Преимущества:
Возможность добавления и удаления элементов (изменение размера списка)
Размер ограничен доступной оперативной памятью
Недостатки:
Сложность получения элемента по индексу Дополнительный расход памяти на хранение указателей
Нелокальное хранение данных списка (снижает вероятность кеширования)
Сложность в выполнении параллельной обработки
Узел списка
Узел списка представляет собой составную структуру. Обычно реализуется с помощью класса или структуры (в процедурных языках). Содержит значения двух типов: одно для хранения данных (числа, строки и т. д.), второе — это ссылка на следующий узел
(реализуется как указатель или ссылка, тип которых совпадает с типом узел). Из-за того, что на момент компиляции количество узлов списка не известно, память для их хранения должна выделяться динамически (т. е. использовать heap).
Односвязный список
В простейшем случае односвязный список состоит из структуры, хранящей одну ссылку на узел. Такая ссылка называется головой списка (head). Существует два подхода относительно головы списка. В первом случае эта ссылка не инициализирована (равна null, None и т. д.), во втором подходе она указывает на фиктивный узел (создаётся при инициализации списка). При добавлении значений в список голова списка указывает на следующий узел в списке (который указывает на следующий узел и т. д.). Такая структура дополняется рядом методов (функций) для добавления, удаления, получения узлов.
Добавление значения в начало списка
Добавление значения в конец списка. Список пуст
