{
 "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
}
