[1] Add report 1 exercize
This commit is contained in:
parent
535fd115b5
commit
b8b7971d86
BIN
SavelevMI/docs/performance_comparison.png
Normal file
BIN
SavelevMI/docs/performance_comparison.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
82
SavelevMI/docs/report-1.md
Normal file
82
SavelevMI/docs/report-1.md
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
# Отчёт по лабораторной работе «Структуры данных»
|
||||||
|
|
||||||
|
## Цель работы
|
||||||
|
|
||||||
|
Реализовать три структуры данных «с нуля» (связный список, хеш‑таблицу, двоичное дерево поиска) для хранения записей телефонного справочника. Экспериментально сравнить производительность операций вставки, поиска и удаления на наборе из 10 000 записей при случайном и отсортированном порядке поступления данных.
|
||||||
|
|
||||||
|
## Реализованные структуры
|
||||||
|
|
||||||
|
Все структуры написаны в процедурном стиле без использования классов.
|
||||||
|
|
||||||
|
1. **Связный список** – узлы в виде словарей `{'name': str, 'phone': str, 'next': None}`.
|
||||||
|
2. **Хеш‑таблица** – массив из 10 корзин, каждая корзина – связный список. Хеш‑функция – `hash(name) % size`.
|
||||||
|
3. **Двоичное дерево поиска** – узлы `{'name': str, 'phone': str, 'left': None, 'right': None}`. Операции реализованы рекурсивно.
|
||||||
|
|
||||||
|
## Методика эксперимента
|
||||||
|
|
||||||
|
- **Генерация данных**: 10 000 записей с именами `User_00001` … `User_10000`. Телефоны – случайные строки вида `XXX-XXXX`.
|
||||||
|
- **Два режима подачи данных**:
|
||||||
|
– *Случайный* – записи перемешаны.
|
||||||
|
– *Отсортированный* – записи по возрастанию имени.
|
||||||
|
- **Измеряемые операции**:
|
||||||
|
– Вставка всех 10 000 записей.
|
||||||
|
– Поиск 110 имён (100 существующих + 10 несуществующих).
|
||||||
|
– Удаление 50 случайных существующих записей.
|
||||||
|
- **Повторы**: каждый эксперимент выполнен 5 раз, зафиксировано среднее время.
|
||||||
|
|
||||||
|
Результаты замеров сохранены в `experiment_results.csv`. Время измерялось через `time.perf_counter()`.
|
||||||
|
|
||||||
|
## Результаты измерений
|
||||||
|
|
||||||
|
### Связный список (LinkedList)
|
||||||
|
|
||||||
|
При 10 000 записях связный список показал ожидаемо низкую производительность. Вставка всех элементов заняла около **4.4 секунды** в среднем, поиск – около **0.027 секунды**, удаление 50 записей – около **0.012 секунды**. Порядок входных данных практически не повлиял на результаты (случайный и отсортированный режимы показали близкие значения). Это объясняется тем, что связный список всегда работает за линейное время O(n) независимо от того, как приходят данные.
|
||||||
|
|
||||||
|
### Хеш‑таблица (HashTable)
|
||||||
|
|
||||||
|
Хеш‑таблица с 10 корзинами показала значительное ускорение по сравнению со связным списком. Вставка 10 000 записей заняла в среднем **0.56 секунды** (почти в 8 раз быстрее списка). Поиск выполняется за **0.004 секунды** (в 7 раз быстрее), а удаление – за **0.0016 секунды** (в 7.5 раз быстрее). Порядок данных практически не влияет на производительность – разница между случайным и отсортированным режимами не превышает 10%, что соответствует теоретической сложности O(1) в среднем.
|
||||||
|
|
||||||
|
### Двоичное дерево поиска (BST)
|
||||||
|
|
||||||
|
Здесь наблюдается самая интересная картина:
|
||||||
|
|
||||||
|
**На случайных данных** BST показал выдающуюся производительность. Вставка всех 10 000 записей заняла всего **0.025 секунды**, что в 22 раза быстрее хеш‑таблицы и в 176 раз быстрее связного списка. Поиск выполняется за **0.00024 секунды** (в 16 раз быстрее хеш‑таблицы), удаление – за **0.00017 секунды** (почти в 10 раз быстрее). Это идеальный случай сбалансированного дерева.
|
||||||
|
|
||||||
|
**На отсортированных данных** ситуация кардинально меняется. Дерево вырождается в линейный список, и производительность падает катастрофически. Вставка замедлилась до **10.15 секунды** – это в 406 раз медленнее, чем на случайных данных, и даже медленнее, чем у связного списка (в 2.3 раза). Поиск вырос до **0.091 секунды** (в 380 раз медленнее), удаление – до **0.057 секунды** (в 335 раз медленнее). Это классический пример деградации BST при упорядоченных входных данных.
|
||||||
|
|
||||||
|
## Анализ результатов
|
||||||
|
|
||||||
|
### Как порядок входных данных влияет на скорость вставки в BST
|
||||||
|
|
||||||
|
Эксперимент наглядно демонстрирует проблему наивной реализации двоичного дерева поиска. На случайных данных дерево остаётся достаточно сбалансированным, и операции выполняются за логарифмическое время (O(log n)). Однако на отсортированных данных каждый новый элемент становится самым большим и добавляется только в правую ветку. В результате дерево превращается в односвязный список высотой 10 000 узлов, а сложность всех операций деградирует до линейной O(n). Это подтверждается цифрами: время вставки выросло с 0.025 до 10.15 секунд – разница в 406 раз.
|
||||||
|
|
||||||
|
### Почему хеш‑таблица почти не чувствительна к порядку
|
||||||
|
|
||||||
|
Хеш‑функция распределяет ключи по корзинам независимо от того, в каком порядке они поступают. «User_00001» и «User_10000» с равной вероятностью могут попасть в любую из 10 корзин. Поэтому порядок ввода не влияет на длину цепочек в каждой корзине. Результаты подтверждают это: в случайном и отсортированном режимах время выполнения операций отличается незначительно (менее 10%).
|
||||||
|
|
||||||
|
### Почему связный список всегда медленен при поиске
|
||||||
|
|
||||||
|
Связный список не имеет индексов или другой структуры для ускорения доступа. Чтобы найти элемент, нужно в худшем случае пройти все 10 000 узлов. Поэтому поиск занимает ~0.027 секунды независимо от того, как расположены данные. Вставка тоже требует прохода до конца списка, что даёт ~4.4 секунды на 10 000 элементов.
|
||||||
|
|
||||||
|
### Как удаление работает в каждой структуре
|
||||||
|
|
||||||
|
Удаление тесно связано с поиском, потому что сначала нужно найти удаляемый элемент. Поэтому время удаления коррелирует со временем поиска:
|
||||||
|
|
||||||
|
- В связном списке удаление занимает ~0.012 секунды – примерно половину времени поиска (0.027 с), так как операция перелинковки дёшева.
|
||||||
|
- В хеш‑таблице удаление (~0.0016 с) близко ко времени поиска (~0.004 с), опять же с поправкой на перелинковку в списке корзины.
|
||||||
|
- В BST на случайных данных удаление (~0.00017 с) даже быстрее поиска (~0.00024 с) из-за особенностей рекурсивной реализации.
|
||||||
|
- В BST на отсортированных данных удаление (~0.057 с) занимает примерно половину времени поиска (~0.091 с) – та же закономерность, что и у списка, потому что вырожденное дерево ведёт себя как список.
|
||||||
|
|
||||||
|
## Выводы
|
||||||
|
|
||||||
|
**Какую структуру и для каких задач стоит выбирать в реальной жизни?**
|
||||||
|
|
||||||
|
1. **Хеш‑таблица** – оптимальный выбор для подавляющего большинства сценариев, где нужен быстрый доступ по ключу (словари, кэши, индексы в базах данных). Она стабильна, предсказуема и не зависит от порядка данных. В моём эксперименте она уступила BST на случайных данных, но выиграла у BST на отсортированных и оказалась намного быстрее связного списка. Главный минус – отсутствие естественного порядка при обходе.
|
||||||
|
|
||||||
|
2. **Сбалансированное дерево** (AVL или красно-чёрное) – выбор, когда нужны оба свойства: быстрый доступ (O(log n)) и возможность получать данные в отсортированном порядке без дополнительной сортировки. Обычный BST (как в моей реализации) **использовать не стоит**, если нельзя гарантировать случайный порядок входных данных. Деградация на упорядоченных данных делает его непригодным для реальных систем.
|
||||||
|
|
||||||
|
3. **Связный список** – практически бесполезен для хранения больших объёмов данных. Единственное оправданное применение – очень маленькие коллекции (до сотни элементов), реализация очередей/стеков или учебные цели.
|
||||||
|
|
||||||
|
**Рекомендация**: если нужен только быстрый доступ по ключу – берите хеш-таблицу. Если нужен отсортированный вывод и вы готовы пожертвовать небольшой долей производительности – используйте сбалансированное дерево. От наивного BST и связного списка в реальных проектах лучше отказаться.
|
||||||
|
|
||||||
|
**Ключевой вывод эксперимента**: порядок поступления данных критически важен для производительности BST (разница в 400 раз между случайными и отсортированными данными), но почти не влияет на хеш-таблицу и связный список (хотя последний всегда медленный).
|
||||||
Loading…
Reference in New Issue
Block a user