2026-rff_mp/stepushovgs/data-structures/docs/Отчёт.md

123 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## Практические графики
### Информация о тестировании
- Общее число записей: 20000
- Каждый замер повторялся: 20 раз
- Количество существующих записей для случайного поиска: 1000
- Количество несуществующих записей для поиска: 500
- Количество элементов для удаления: 1000
![[insert.pdf]]
**Тестирование вставки (рис. 1)**
![[search.pdf]]
**Тестирование поиска (рис. 2)**
![[delete.pdf]]
**Тестирование удаления (рис. 3)**
## Анализ результатов
### Как порядок входных данных влияет на скорость вставки в BST (деградация до O(n) на отсортированных данных)?
По определению, при вставке отсортированных данных, структура бинарного дерева поиска вырождается в связный список.
Для визуализации этого в тесте выводятся высота и количество элементов в дереве:
Для случайных данных вывод выглядит примерно так:
```
Высота дерева: 28, элементов: 8634
```
Для сортированных данных же:
```
Высота дерева: 8634, элементов: 8634
```
Заметим, что при случайных данных скорость вставки в бинарное дерево почти лишь немного уступает по скорости хеш-таблице. При сортированных данных из-за рекурсивной реализации вставки бинарное дерево проигрывает связному списку(который имеет линейную сложность вставки)
### Почему хеш-таблица почти не чувствительна к порядку.
Хеш-таблица не чувствительна к порядку данных, так как использует для распределения элементов хеш значения данных (сложность операции одинакова для любых однотипных данных) и после производит вставку в связный список(в моей реализации проходит по списку и вставляет данные в конец). Поэтому хеш-таблица ни на одном из этапов не сравнивает данные, следовательно их порядок не влияет на скорость.
### Почему связный список всегда медленен при поиске.
Операция поиска в связном списке имеет линейную сложность $O(n)$ не зависимо от порядка данных, что можно видеть на графике (см. рис. 2). Для бинарного дерева поиска эта сложность в лучшем случае $O(\log(N))$, а в худшем $O(N)$. Для хеш-таблицы сложность вставки $O(1)$, с хорошей хеш-функцией и низким заполнением.
### Как удаление работает в каждой структуре.
#### Связный список
Находим элемент перед удаляем элементом, и заменяем его поле `next` на `next.next`, то есть теперь он указывает на элемент, который идёт после удаляемого элемента
``` Go
current := ll.head
for current.next != nil {
if current.next.data.Name == targetName {
current.next = current.next.next
return true
}
current = current.next
}
```
#### Бинарное дерево поиска
После того, как мы нашли узел, который необходимо удалить, у нас возможны три случая.
Случай 1: У удаляемого узла нет правого ребенка.
В этом случае мы просто перемещаем левого ребенка (3) на место удаляемого узла(5). В результате дерево будет выглядеть так:
```
Удаляем элемент со значением 5
ДО УДАЛЕНИЯ: ПОСЛЕ УДАЛЕНИЯ:
[8] [8]
/ \ / \
[5] [10] [3] [10]
/ / \
[3] [1] [4]
/ \
[1] [4]
```
Случай 2: У удаляемого узла есть только правый ребенок, у которого, в свою очередь нет левого ребенка.
В этом случае нам надо переместить правого ребенка(8) удаляемого узла (5) на его место.
```
Удаляем элемент со значением 5
До удаления: После удаления:
[10] [10]
/ \ / \
[5] [12] [8] [12]
/ \ / \
[1] [8] [1] [9]
\
[9]
```
Случай 3: У удаляемого узла есть первый ребенок, у которого есть левый ребенок.
В этом случае место удаляемого узла занимает крайний левый ребенок правого ребенка удаляемого узла.
Давайте посмотрим, почему это так. Мы знаем о поддереве, начинающемся с удаляемого узла следующее:
- Все значения справа от него больше или равны значению самого узла.
- Наименьшее значение правого поддерева — крайнее левое.
Мы должны поместить на место удаляемого узел со значением, меньшим или равным любому узлу справа от него. Для этого нам необходимо найти наименьшее значение в правом поддереве. Поэтому мы берем крайний левый узел правого поддерева.
```
Удаляем элемент со значением 5
До удаления: После удаления:
[10] [10]
/ \ / \
[5] [12] [7] [12]
/ \ / \
[1] [9] [1] [9]
/ /
[7] [8]
\
[8]
```
#### Хеш-таблица
Находим индекс элемента в таблица, далее производим удаление элемента в связном списке, который соответствует этому индексу.
# Вывод
Мы реализовали и протестировали три различные структуры хранения данных: связный список, бинарное дерево поиска и хеш-таблица. Сравнили скорость операций вставки, удаления и поиска для каждой структуры.
Если не важен порядок хранения и извлечения данных, то хеш-таблица лучший выбор для быстрых вставки, удаления и поиска.
Если нужно хранить данные с возможностью быстрого отсортированного обхода, то стоит выбрать бинарное дерево поиска.
Если нужно хранить данные в порядке поступления(например очередь), то стоит выбрать связный список.