[1] data structures #182
2
lomakinae/.gitignore
vendored
Normal file
2
lomakinae/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
__pycache__/
|
||||
*.pyc
|
||||
86
lomakinae/docs/01_report.md
Normal file
86
lomakinae/docs/01_report.md
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# Отчёт. Задание 1 - структуры данных
|
||||
|
||||
## Цель
|
||||
|
||||
Реализовать три структуры данных (связный список, хеш-таблица, BST) и экспериментально сравнить их
|
||||
производительность на операциях insert / find / delete при случайном и отсортированном порядке входных
|
||||
данных.
|
||||
|
||||
## Параметры эксперимента
|
||||
|
||||
| Параметр | Значение |
|
||||
| ----------- | ------------------------------------ |
|
||||
| N (записей) | 10 000 |
|
||||
| Повторений | 5 |
|
||||
| Поисков | 100 существующих + 10 несуществующих |
|
||||
| Удалений | 50 |
|
||||
|
||||
---
|
||||
|
||||
## Результаты
|
||||
|
||||
### Случайные данные (shuffled)
|
||||
|
||||

|
||||
|
||||
### Отсортированные данные (sorted)
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Анализ
|
||||
|
||||
### Деградация BST на отсортированных данных
|
||||
|
||||

|
||||
|
||||
На случайных данных BST - самая быстрая структура: insert 0.027 с. Случайный порядок вставки даёт сбалансированное
|
||||
дерево глубиной ~log N, поэтому каждый новый узел находит своё место за O(log N) шагов. На отсортированных - 12.77 с,
|
||||
то есть в ~473 раз медленнее. Причина: при последовательной вставке отсортированных ключей каждый новый узел уходит в
|
||||
правое поддерево предыдущего. Дерево вырождается в цепочку глубиной N, и каждая вставка требует O(N) шагов вместо O(log N).
|
||||
|
||||
### Хеш-таблица нечувствительна к порядку
|
||||
|
||||
HashTable показывает практически одинаковое время в обоих режимах (insert: 0.033 с против 0.032 с). Это ожидаемо:
|
||||
индекс бакета вычисляется через `hash(name)`, который не зависит от порядка вставки. Операции работают за O(1)
|
||||
при любом входе.
|
||||
|
||||
### Связный список медленен при поиске
|
||||
|
||||
LinkedList не имеет никакой структуры для навигации - единственный способ найти запись это пройти список от головы до нужного узла.
|
||||
Find всегда O(N) независимо от порядка данных: shuffled 0.041 с, sorted 0.039 с. Insert O(N^2) для всей выборки - перед каждой вставкой
|
||||
нужно пройти весь список для проверки дубликата. На отсортированных данных LinkedList не меняет поведение, тогда как BST деградирует
|
||||
до 12.77 с - в этом единственном сценарии LinkedList оказывается быстрее BST.
|
||||
|
||||
### Удаление
|
||||
|
||||
LinkedList - чтобы удалить узел, нужно пройти список от головы до нужного элемента и перешить next предшественника.
|
||||
Это O(N) в любом случае, порядок данных не имеет значения. Shuffled: 0.027 с, sorted: 0.026 с - разница в пределах погрешности.
|
||||
|
||||
HashTable - вычисляем индекс бакета через `hash(name)`, затем удаляем узел из связного списка этого бакета. Порядок вставки не
|
||||
влияет на то, в каком бакете лежит запись, поэтому время стабильно в обоих режимах: 0.00033 с.
|
||||
|
||||
BST - ищем узел спуском по дереву, затем обрабатываем три случая: нет потомков, один потомок, два потомка. На случайных данных
|
||||
дерево сбалансировано, глубина ~log N, удаление занимает 0.00014 с. На отсортированных данных дерево вырождено в
|
||||
цепочку - каждый узел уходил в правое поддерево при вставке, поэтому поиск удаляемого узла проходит через всю цепочку O(N).
|
||||
Результат: 0.061 с, то есть в ~435 раз медленнее.
|
||||
|
||||
---
|
||||
|
||||
## Вывод
|
||||
|
||||
**Частые вставки** - HashTable. Время вставки не зависит от порядка и объёма данных: индекс бакета вычисляется за O(1),
|
||||
вставка в бакет - тоже O(1). Подтверждают цифры: 0.033 с на shuffled и 0.032 с на sorted при N=10000.
|
||||
|
||||
**Частый поиск** - HashTable. По той же причине: `hash(name)` сразу указывает на нужный бакет, линейный перебор не нужен.
|
||||
Find: 0.00057 с на shuffled, 0.00070 с на sorted - стабильно при любом входе.
|
||||
|
||||
**Получить данные в отсортированном порядке** - BST при случайном порядке вставки. Элементы размещаются по правилу BST
|
||||
(слева меньшие корня, справа большие корня), поэтому обход по схеме левое поддерево -> корень -> правое поддерево возвращает
|
||||
все записи в алфавитном порядке без дополнительной сортировки. Важное условие: данные должны вставляться в случайном
|
||||
порядке, иначе дерево вырождается (см. деградацию BST на отсортированных данных).
|
||||
|
||||
LinkedList сам по себе проигрывает по всем операциям из-за O(N\*\*2) на вставку и O(N) на поиск. Однако его идея лежит в основе
|
||||
хеш-таблицы: каждый бакет - это связный список, через который разрешаются коллизии. Как самостоятельная структура данных для
|
||||
справочника он неэффективен, но как строительный блок внутри HashTable - незаменим.
|
||||
9
lomakinae/docs/data/01/README.md
Normal file
9
lomakinae/docs/data/01/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Задание 1: структуры данных
|
||||
|
||||
## Как запустить
|
||||
```sh
|
||||
python main.py
|
||||
```
|
||||
|
||||
## Результаты
|
||||
Графики генерируются автоматически в папку `attachments/`.
|
||||
BIN
lomakinae/docs/data/01/attachments/plot_bst_comparison.png
Normal file
BIN
lomakinae/docs/data/01/attachments/plot_bst_comparison.png
Normal file
Binary file not shown.
BIN
lomakinae/docs/data/01/attachments/plot_shuffled.png
Normal file
BIN
lomakinae/docs/data/01/attachments/plot_shuffled.png
Normal file
Binary file not shown.
BIN
lomakinae/docs/data/01/attachments/plot_sorted.png
Normal file
BIN
lomakinae/docs/data/01/attachments/plot_sorted.png
Normal file
Binary file not shown.
6
lomakinae/docs/data/01/main.py
Normal file
6
lomakinae/docs/data/01/main.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
from src.experiment import main_experiment
|
||||
from src.plot import build_plots
|
||||
|
||||
if __name__ == "__main__":
|
||||
main_experiment()
|
||||
build_plots()
|
||||
91
lomakinae/docs/data/01/results.csv
Normal file
91
lomakinae/docs/data/01/results.csv
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
structure,mode,operation,run,time_sec
|
||||
LinkedList,shuffled,insert,1,3.25562
|
||||
LinkedList,shuffled,find,1,0.040773
|
||||
LinkedList,shuffled,delete,1,0.026344
|
||||
HashTable,shuffled,insert,1,0.033497
|
||||
HashTable,shuffled,find,1,0.000593
|
||||
HashTable,shuffled,delete,1,0.000348
|
||||
BST,shuffled,insert,1,0.024071
|
||||
BST,shuffled,find,1,0.000218
|
||||
BST,shuffled,delete,1,0.000136
|
||||
LinkedList,shuffled,insert,2,3.454281
|
||||
LinkedList,shuffled,find,2,0.040282
|
||||
LinkedList,shuffled,delete,2,0.026526
|
||||
HashTable,shuffled,insert,2,0.031691
|
||||
HashTable,shuffled,find,2,0.000568
|
||||
HashTable,shuffled,delete,2,0.000338
|
||||
BST,shuffled,insert,2,0.024978
|
||||
BST,shuffled,find,2,0.000213
|
||||
BST,shuffled,delete,2,0.000135
|
||||
LinkedList,shuffled,insert,3,3.453681
|
||||
LinkedList,shuffled,find,3,0.0404
|
||||
LinkedList,shuffled,delete,3,0.026843
|
||||
HashTable,shuffled,insert,3,0.031902
|
||||
HashTable,shuffled,find,3,0.000536
|
||||
HashTable,shuffled,delete,3,0.000319
|
||||
BST,shuffled,insert,3,0.025369
|
||||
BST,shuffled,find,3,0.000219
|
||||
BST,shuffled,delete,3,0.000138
|
||||
LinkedList,shuffled,insert,4,3.417185
|
||||
LinkedList,shuffled,find,4,0.040816
|
||||
LinkedList,shuffled,delete,4,0.027023
|
||||
HashTable,shuffled,insert,4,0.037826
|
||||
HashTable,shuffled,find,4,0.000582
|
||||
HashTable,shuffled,delete,4,0.00033
|
||||
BST,shuffled,insert,4,0.036423
|
||||
BST,shuffled,find,4,0.000227
|
||||
BST,shuffled,delete,4,0.00014
|
||||
LinkedList,shuffled,insert,5,3.4723
|
||||
LinkedList,shuffled,find,5,0.040734
|
||||
LinkedList,shuffled,delete,5,0.027866
|
||||
HashTable,shuffled,insert,5,0.031981
|
||||
HashTable,shuffled,find,5,0.000546
|
||||
HashTable,shuffled,delete,5,0.000332
|
||||
BST,shuffled,insert,5,0.024578
|
||||
BST,shuffled,find,5,0.000227
|
||||
BST,shuffled,delete,5,0.000146
|
||||
LinkedList,sorted,insert,1,3.271489
|
||||
LinkedList,sorted,find,1,0.038886
|
||||
LinkedList,sorted,delete,1,0.026646
|
||||
HashTable,sorted,insert,1,0.030995
|
||||
HashTable,sorted,find,1,0.000625
|
||||
HashTable,sorted,delete,1,0.000302
|
||||
BST,sorted,insert,1,13.000812
|
||||
BST,sorted,find,1,0.128239
|
||||
BST,sorted,delete,1,0.06369
|
||||
LinkedList,sorted,insert,2,3.384572
|
||||
LinkedList,sorted,find,2,0.03915
|
||||
LinkedList,sorted,delete,2,0.026683
|
||||
HashTable,sorted,insert,2,0.032596
|
||||
HashTable,sorted,find,2,0.0006
|
||||
HashTable,sorted,delete,2,0.000315
|
||||
BST,sorted,insert,2,12.593249
|
||||
BST,sorted,find,2,0.10657
|
||||
BST,sorted,delete,2,0.058763
|
||||
LinkedList,sorted,insert,3,3.27816
|
||||
LinkedList,sorted,find,3,0.038938
|
||||
LinkedList,sorted,delete,3,0.025567
|
||||
HashTable,sorted,insert,3,0.03168
|
||||
HashTable,sorted,find,3,0.000631
|
||||
HashTable,sorted,delete,3,0.00031
|
||||
BST,sorted,insert,3,12.809241
|
||||
BST,sorted,find,3,0.110947
|
||||
BST,sorted,delete,3,0.062604
|
||||
LinkedList,sorted,insert,4,3.277437
|
||||
LinkedList,sorted,find,4,0.039812
|
||||
LinkedList,sorted,delete,4,0.025627
|
||||
HashTable,sorted,insert,4,0.031844
|
||||
HashTable,sorted,find,4,0.000917
|
||||
HashTable,sorted,delete,4,0.000383
|
||||
BST,sorted,insert,4,12.722063
|
||||
BST,sorted,find,4,0.111841
|
||||
BST,sorted,delete,4,0.060014
|
||||
LinkedList,sorted,insert,5,3.261706
|
||||
LinkedList,sorted,find,5,0.037981
|
||||
LinkedList,sorted,delete,5,0.025241
|
||||
HashTable,sorted,insert,5,0.032067
|
||||
HashTable,sorted,find,5,0.000742
|
||||
HashTable,sorted,delete,5,0.000342
|
||||
BST,sorted,insert,5,12.713176
|
||||
BST,sorted,find,5,0.108333
|
||||
BST,sorted,delete,5,0.059109
|
||||
|
Gitea Version: 1.22.0 |
