# Отчет по лабораторной работе "Структуры данных"
## 1. Введение
В ходе выполнения лабораторной работы были выполнены реализации трех структур для хранения и обработки данных телефонных номеров:
- Связный список
- Хеш-таблица
- Двоичное дерево поиска.

Практическая часть включала в себя такие операции как: добавление или обновление телефонного номера, удаление телефонного номера, поиск владельца телефонного номера и составление списка из кортежей вида (владелец, номер). Каждое выполнение функций проводилось с списоком из кортежей вида (владелецб номер), в котором было 1000 уникальных имен и еще 9000 имен, которые уже были использованны (всего 10000 кортежей). Каждое тестирование структур выполнялось для сортированного и не сортированного начального списка 10 раз.
## 2. Результаты измерений
Данные в таблице отражают среднее время в милисекундах выполнения структур. 
| Структура | Начальный список | insert, мс | find, мс | delete, мс | create list, мс |
| :---: | :---: | ---: | ---: | ---: | ---: |
| LinkedList | not sorted |  165.61 | 1.767 | 3.418 | 31.795 |
| LinkedList | sorted | 171.01 | 1.720 | 3.440 | 21.378 |
| HashTable | not sorted | 17.15 | 0.278 | 0.320 | 48.080 |
| HashTable | sorted | 17.49 | 0.284 | 0.321 | 47.911 |
| BST | not sorted | 52.95 | 0.772 | 0.660 | 0.283 |
| BST | sorted | 162.70 | 1.809 | 1.564 | 1.626 |

Изходя  из полученных значений можно построить столбчатую диаграмму:

![](data/time_schedule.png)
## 3. Анализ полученных данных
### 3.1 Зависимость скорости работы BST от порядка ввода данных.
Из полученных данных можно заметить, что для BST порядок ввода сильно сказывается на результате скорости выполнения программы: при послутплении неотсортированных данных программа справляется примерно в 3 раза быстрее. Связано это с тем, что каждое новое значение, при сортированных данных, будет больше предыдущего, а соответственно будет каждый раз создаватся правый лист, из-за чего высота дерева становится равной количесвту всех уникальных имен, вседствии чего сложность возрастает до О(n), а двоичное дерево превращается в своебразный связный список. 

### 3.2 Независимость скорости выполнения заполнения хеш-таблицы от порядка вводных данных
Из эксперемента можно заметить, что скорость заполнения хеш-таблицы сортированными и несортированными данными почти одинакова(разница менее 2%). Это объясняется наличием бакетов, которые разбивают все данные на N списков (В данной лабораторной работе N = 100) и не зависмо от способа подачи данных мы всегда получим N списков с одинаков наполнением. 
Скорость выполнения вставки почти одинакова, так как и для случая сортированного и несортированного начального списка необходимо только определить нужный бакет и добавить в этот бакет кортеж (владелец, номер), то есть сложность операции О(1), что отражают результаты эксперемента.
Скорость выполнения поиска/удаления/составление списка почти одинаковы по тем же причинам: из-за наличия бакетов отрезаем часть лишних данных и уже работаем с оставшимеся, что значительно уменьшает время, а так как длина списока в бакете будет гораздо меньше длины списка исходных данных, что линейная сложность при переборе этого списка не сильно повлияет на время выполнения программы.

### 3.3 Медленность посика связного списка
Чтобы найти нужный элемент в связном списке необходимо перебрать все элементы стоящие до него, и если элемент находится где-то в конце такого списка, то придется перебрать почти все значения, на что уйдет явно больше премени чем при применениеи хеш-таблицы, которая отсекает большую часть ненужных данных, или двоичного дерева, которое составлено так, что не нужно будет перебирать все значения. 

### 3.4 Принципы работы Удаления
### - Связный список:
В связном списке необходимо найти нужный словарь, значение ключа next содержит искомое имя. После этого мы меняем значение ключа next этого словаря на то, которое стоит в значении ключа next словаря, который мы собираемся удалить. Если мы хотим удалить запись, которой не существует, в таком случае перебираем весь связный спискок полностью и в случае ненахождения нужной записи возвращаем исходный список.

### - Хеш-таблица:
В начале ищем номер нужного бакета, и начинаем искать в бакете необходую запись: перебираем список кортежей, пока не найдем нужную запись. Если запись нашлась, то удалем ее и списка, если нет, то возвращаем исходные данные без изменений

### - Двоичное дерево посика:
Сначала ищем узел, который необходимо удалить, а затем действуем в зависимости от ситуации:
- 1 У узла нет потомков:
    В такой ситуации просто удаляем наш узел(в данном случае лист)
- 2 У узла нет потомков справа или слева:
    Если у узла есть только правые потомки, то на место этого узела помещаем узел, который расположен справа. Аналогично для случая с наличием левых потомков.
- 3 Если у узла есть и правые и левые потомки:
    Находим самый маленький узел в правом поддереве этого узла, то есть идем сначала вправо от узла, а потом только влево, пока не дойдем до значения None.
    Копируем значения этого наименьшего и подставляем эти данные в узел, который хотим удалить, не меняя значения под ключами left и  right, а затем удаляем этот наименьший как описано в пунктах (1) и (2), так как этот узел или будет иметь только потомков вправа или не иметь их вообще

## Вывод: в ходе выполнения лабораторной были изучены 3 способа хранения и обработки данных. Из данных полученных из эксперементов можно выделить наилучшие способы применения этих структур. Если в программе необходимо часто пополнять данные, корректировать, искать и удалять их, то лучше всего подойдет хеш-таблица. Если необходимо часто собирать все данные в один сортированный список и исходные данные несортированные, то хеш-таблица будет тормозить, в этом случае лучше использовать двоичное дерего поиска, хоть они и показывают более худший результат в добавлении, посике и удалении(примерно в 2.5-3 раза), но формируют список они моментально: 0.283 мс. Если же исходные данные отсортированны и необходимо выполнять все те же операции но без удаления, то в таком случае наиболее эффективным будет связный список.