2026-rff_mp/zverevem/lab1/docs/отчёт.ipynb
2026-05-14 13:18:29 +03:00

164 lines
11 KiB
Plaintext
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.

{
"cells": [
{
"cell_type": "markdown",
"id": "f058dc2c",
"metadata": {},
"source": [
"# Отчёт: Задание 1 — Структуры данных\n",
"\n",
"## Цель работы\n",
"\n",
"Разработать три структуры данных «с нуля» в процедурном стиле (без ООП), применить их для хранения записей телефонной книги и провести экспериментальное сравнение производительности ключевых операций.\n",
"\n",
"**Структуры данных:**\n",
"- Связный список (LinkedList)\n",
"- Хеш-таблица (HashTable)\n",
"- Двоичное дерево поиска (BST)\n",
"\n",
"---\n",
"\n",
"## Реализация\n",
"\n",
"### Основные технические решения\n",
"\n",
"#### 1. Связный список\n",
"\n",
"Узел реализован как Python-словарь: `{'name': 'Имя', 'phone': '123', 'next': None}`.\n",
"\n",
"Новые элементы добавляются **в конец** списка за O(1) (без проверки на дубликаты имени). Поиск и удаление работают за линейное время O(n) из-за отсутствия прямого доступа по индексу.\n",
"\n",
"#### 2. Хеш-таблица\n",
"\n",
"Фиксированный массив на **1000 корзин**. Каждая корзина — указатель на связный список (метод цепочек). Хеш-функция: полиномиальная с основанием 31, свёрнутая по модулю размера таблицы. Среднее время операций O(1), при коллизиях — O(k), где k — длина цепочки.\n",
"\n",
"#### 3. Двоичное дерево поиска (BST)\n",
"\n",
"Узел: `{'name': 'Имя', 'phone': '123', 'left': None, 'right': None}`. Сравнение ключей — лексикографическое по полю `name`. Вставка и поиск реализованы итеративно. Удаление — с заменой на минимальный узел правого поддерева. Обход в глубину даёт отсортированный список.\n",
"\n",
"---\n",
"\n",
"## Экспериментальная часть\n",
"\n",
"### Условия проведения замеров\n",
"\n",
"| Параметр | Значение |\n",
"|---|---|\n",
"| Количество записей (N) | 10 000 |\n",
"| Количество замеров на операцию | 5 |\n",
"| Поисковых запросов | 110 (100 существующих + 10 отсутствующих) |\n",
"| Удалений | 50 |\n",
"| Размер хеш-таблицы | 1000 корзин |\n",
"\n",
"**Два набора данных:**\n",
"- `records_shuffled` — случайный порядок записей\n",
"- `records_sorted` — упорядоченный по имени (алфавитный порядок)\n",
"\n",
"---\n",
"\n",
"## Результаты\n",
"\n",
"### Среднее время выполнения (секунды)\n",
"\n",
"| Структура | Режим | Вставка (10000) | Поиск (110) | Удаление (50) |\n",
"|-----------|-------|----------------|-------------|---------------|\n",
"| LinkedList | случайный | 0.001383 | 0.00000514 | 0.00000234 |\n",
"| LinkedList | отсортированный | 0.001167 | 0.00000500 | 0.00000230 |\n",
"| HashTable | случайный | 0.010394 | 0.00009380 | 0.00004332 |\n",
"| HashTable | отсортированный | 0.009557 | 0.00009298 | 0.00004388 |\n",
"| BST | случайный | 0.015142 | 0.00013682 | 0.00007188 |\n",
"| **BST** | **отсортированный** | **4.19062** | **0.030306** | **0.016941** |\n",
"\n",
"### Визуализация\n",
"\n",
"![Сравнение вставки](docs/data/graph_insert.png)\n",
"\n",
"![Сравнение поиска](docs/data/graph_search.png)\n",
"\n",
"![Сравнение удаления](docs/data/graph_delete.png)\n",
"\n",
"![Таблица результатов](docs/data/table_results.png)\n",
"\n",
"---\n",
"\n",
"## Анализ результатов\n",
"\n",
"### 1. Связный список — сверхбыстрая вставка, но линейный поиск\n",
"\n",
"- **Вставка** выполняется за **~0.0012 с** на 10000 элементов, так как добавление происходит в конец списка без проверки дубликатов (O(1) на операцию).\n",
"- **Поиск** и **удаление** в замерах показали микросекунды, но это следствие малого количества операций (110 поисков, 50 удалений) и того, что искомые записи находятся в начале списка. В худшем случае (поиск отсутствующего элемента) сложность остаётся O(n).\n",
"\n",
"**Вывод:** связный список эффективен только при очень малых объёмах данных или когда вставка — единственная частая операция.\n",
"\n",
"### 2. Хеш-таблица — стабильная производительность\n",
"\n",
"Хеш-таблица демонстрирует **устойчивость к порядку входных данных**:\n",
"- Вставка: ~0.010 с (быстрее BST на случайных данных, но медленнее LinkedList)\n",
"- Поиск: ~0.000094 с (в 18 раз быстрее BST на случайных)\n",
"- Удаление: ~0.000043 с (в 1.6 раза быстрее BST)\n",
"\n",
"Размер таблицы (1000 корзин) обеспечивает равномерное распределение ключей, поэтому производительность остаётся стабильной.\n",
"\n",
"### 3. BST катастрофически деградирует на упорядоченных данных\n",
"\n",
"Самый показательный результат эксперимента:\n",
"\n",
"| Операция | Случайный порядок | Отсортированный порядок | Ухудшение |\n",
"|----------|------------------|------------------------|-----------|\n",
"| Вставка | 0.01514 с | **4.19062 с** | **×277** |\n",
"| Поиск | 0.0001368 с | **0.03031 с** | **×221** |\n",
"| Удаление | 0.0000719 с | **0.01694 с** | **×236** |\n",
"\n",
"**Причина:** при вставке отсортированных данных дерево вырождается в линейный список — каждый новый элемент больше предыдущего и помещается только в правую ветку. Высота дерева становится O(n) вместо O(log n), что превращает все операции в линейные.\n",
"\n",
"### 4. Сравнение с теоретическими ожиданиями\n",
"\n",
"| Структура | Теоретическая вставка | Фактическая (случ./сорт.) | \n",
"|-----------|----------------------|---------------------------|\n",
"| LinkedList | O(1) (в конец) | 0.0014 с / 0.0012 с |\n",
"| HashTable | O(1) в среднем | 0.0104 с / 0.0096 с |\n",
"| BST | O(log n) в среднем | 0.0151 с (случ.) |\n",
"| BST | O(n) в худшем | 4.19 с (сорт.) |\n",
"\n",
"---\n",
"\n",
"## Выводы и практические рекомендации\n",
"\n",
"### Выбор структуры в зависимости от задачи\n",
"\n",
"| Сценарий | Рекомендация |\n",
"|----------|--------------|\n",
"| **Частый поиск по ключу** | HashTable (быстрее всего) |\n",
"| **Данные поступают упорядоченно** | HashTable (BST непригоден) |\n",
"| **Только вставка и редкий поиск** | LinkedList (самая быстрая вставка) |\n",
"| **Требуется отсортированный вывод** | BST (обход даёт порядок за O(n)) |\n",
"| **Сбалансированные операции** | HashTable |\n",
"| **Диапазонные запросы** (например, АМ) | BST (при условии балансировки) |\n",
"\n",
"### Теоретическая сложность операций \n",
"| Структура | Insert | Find | Delete | Обход (отсорт.) |\n",
"|-----------|--------|------|--------|-----------------|\n",
"| LinkedList (в конец) | O(1) | O(n) | O(n) | O(n log n) |\n",
"| HashTable | O(1) | O(1) | O(1) | O(n log n) |\n",
"| BST (сбалансированный) | O(log n) | O(log n) | O(log n) | O(n) |\n",
"| BST (вырожденный) | O(n) | O(n) | O(n) | O(n) |\n",
"\n",
"### Ключевой вывод\n",
"\n",
"Для телефонного справочника с частыми поисками и обновлениями оптимальный выбор — **хеш-таблица**. Она обеспечивает предсказуемую скорость вне зависимости от порядка данных.\n",
"\n",
"Обычный **связный список** полезен только как вспомогательная структура (например, для цепочек в хеш-таблице) или при минимальном объёме данных.\n",
"\n",
"**Двоичное дерево поиска** без самобалансировки опасно использовать с реальными данными, которые часто бывают частично или полностью упорядоченными. В таких случаях необходимо применять AVL или красно-чёрные деревья.\n"
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}