# Отчёт: Задание 1 — Структуры данных ## Цель работы Разработать три структуры данных «с нуля» в процедурном стиле (без ООП), применить их для хранения записей телефонной книги и провести экспериментальное сравнение производительности ключевых операций. **Структуры данных:** - Связный список (LinkedList) - Хеш-таблица (HashTable) - Двоичное дерево поиска (BST) --- ## Реализация ### Основные технические решения #### 1. Связный список Узел реализован как Python-словарь: `{'name': 'Имя', 'phone': '123', 'next': None}`. Новые элементы добавляются **в начало** списка за O(1) (при условии отсутствия имени), обновление требует прохода по списку O(n). Поиск и удаление работают за линейное время из-за отсутствия прямого доступа по индексу. #### 2. Хеш-таблица Фиксированный массив на 256 корзин. Каждая корзина — указатель на связный список (метод цепочек). Хеш-функция: стандартный `hash(name) % size`. Среднее время операций O(1), при коллизиях — O(k), где k — длина цепочки. #### 3. Двоичное дерево поиска (BST) Узел: `{'name': 'Имя', 'phone': '123', 'left': None, 'right': None}`. Сравнение ключей — лексикографическое по полю name. Вставка и поиск реализованы итеративно. Удаление — рекурсивное с заменой на минимальный узел правого поддерева. Обход в глубину даёт отсортированный список. --- ## Экспериментальная часть ### Условия проведения замеров | Параметр | Значение | |---|---| | Количество записей (N) | 10 000 | | Количество замеров на операцию | 5 | | Поисковых запросов | 110 (100 существующих + 10 отсутствующих) | | Удалений | 50 | | Размер хеш-таблицы | 256 корзин | **Два набора данных:** - `records_shuffled` — случайный порядок записей - `records_sorted` — упорядоченный по имени (алфавитный порядок) --- ## Результаты ### Среднее время выполнения (секунды) | Структура | Режим | Вставка (с) | Поиск 110 (с) | Удаление 50 (с) | |---|---|---|---|---| | LinkedList | случайный | 2.541985 | 0.034289 | 0.020349 | | LinkedList | сортированный | 2.208557 | 0.025340 | 0.016424 | | HashTable | случайный | 0.018235 | 0.000214 | 0.000120 | | HashTable | сортированный | 0.016163 | 0.000207 | 0.000124 | | BST | случайный | 0.017192 | 0.000145 | 0.000104 | | **BST** | **сортированный** | **3.854338** | **0.033498** | **0.045823** | ### Визуализация ![Сравнение по операциям](data/comparison_by_operation.png) ![Влияние порядка данных](data/sorted_vs_random.png) --- ## Анализ результатов ### 1. Связный список — стабильно низкая скорость Вставка требует **~2.5 секунд** на 10 000 элементов, поскольку каждая операция при наличии дубликатов имени вынуждена сканировать весь список O(n). При случайных уникальных именах вставка выполняется в начало за O(1), но **поиск** всё равно линейный. **Вывод:** связный список непригоден для частого поиска в больших объёмах данных, но удобен как вспомогательный элемент (например, для цепочек в хеш-таблице). ### 2. Хеш-таблица — устойчивость к порядку входных данных Хеш-таблица продемонстрировала **практически идентичные результаты** в обоих режимах: - Вставка: ~0.017 с (быстрее списка в ~150 раз) - Поиск: ~0.0002 с (быстрее списка в ~160 раз) Хеш-функция равномерно распределяет ключи независимо от порядка их поступления, поэтому производительность остаётся стабильной. ### 3. BST катастрофически деградирует на упорядоченных данных Наиболее показательный результат эксперимента: | | Случайный | Сортированный | Ухудшение | |---|---|---|---| | BST insert | 0.017 с | **3.854 с** | **×225** | | BST find | 0.000145 с | **0.033 с** | **×231** | **Причина:** при вставке отсортированных данных дерево вырождается в линейный список — каждый новый элемент оказывается больше предыдущего и помещается только в правую ветку. Высота дерева становится O(n) вместо O(log n), что превращает все операции в линейные. ### 4. Операция delete На случайных данных BST удаляет за **~0.0001 с** (логарифмическая сложность). На сортированных — **~0.046 с** (линейная деградация). HashTable показывает стабильные **~0.00012 с** независимо от порядка. --- ## Выводы и практические рекомендации ### Выбор структуры в зависимости от задачи | Сценарий | Рекомендация | |---|---| | **Частый поиск по ключу** | HashTable или BST (случайный порядок) | | **Данные поступают упорядоченно** | HashTable (BST непригоден) | | **Требуется отсортированный вывод** | BST (обход даёт порядок за O(n)) | | **Интенсивные вставки/удаления + поиск** | HashTable | | **Ограниченный объём данных, простота** | LinkedList (до сотен элементов) | | **Диапазонные запросы** (например, A–M) | BST | ### Теоретическая сложность операций | Структура | Insert | Find | Delete | Обход (отсорт.) | |---|---|---|---|---| | LinkedList | O(n) | O(n) | O(n) | O(n log n) | | HashTable | O(1) в среднем | O(1) в среднем | O(1) в среднем | O(n log n) | | BST (сбалансированный) | O(log n) | O(log n) | O(log n) | O(n) | | BST (вырожденный) | O(n) | O(n) | O(n) | O(n) | ### Ключевой вывод Для телефонного справочника с частыми поисками и обновлениями оптимальный выбор — **хеш-таблица**. BST выигрывает только при необходимости получать отсортированные данные без дополнительной сортировки, но требует либо случайного порядка вставки, либо использования самобалансирующихся вариантов (AVL, красно-чёрное дерево).