[1] data structures #182

Merged
VladimirGub merged 11 commits from lomakinae/2026-rff_mp:data_structures into develop 2026-05-30 11:54:51 +00:00
16 changed files with 580 additions and 0 deletions

2
lomakinae/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
__pycache__/
*.pyc

View File

@ -0,0 +1,86 @@
# Отчёт. Задание 1 - структуры данных
## Цель
Реализовать три структуры данных (связный список, хеш-таблица, BST) и экспериментально сравнить их
производительность на операциях insert / find / delete при случайном и отсортированном порядке входных
данных.
## Параметры эксперимента
| Параметр | Значение |
| ----------- | ------------------------------------ |
| N (записей) | 10 000 |
| Повторений | 5 |
| Поисков | 100 существующих + 10 несуществующих |
| Удалений | 50 |
---
## Результаты
### Случайные данные (shuffled)
![shuffled](data/01/attachments/plot_shuffled.png)
### Отсортированные данные (sorted)
![sorted](data/01/attachments/plot_sorted.png)
---
## Анализ
### Деградация BST на отсортированных данных
![bst comparison](data/01/attachments/plot_bst_comparison.png)
На случайных данных 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 - незаменим.

View File

@ -0,0 +1,9 @@
# Задание 1: структуры данных
## Как запустить
```sh
python main.py
```
## Результаты
Графики генерируются автоматически в папку `attachments/`.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,6 @@
from src.experiment import main_experiment
from src.plot import build_plots
if __name__ == "__main__":
main_experiment()
build_plots()

View 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
Internal Server Error - DRE.lab repo

Internal Server Error

Gitea Version: 1.22.0