# Отчёт по лабораторной работе «Структуры данных» ## 1. Цель работы Реализовать три структуры данных «с нуля» без использования классов – связный список, хеш-таблицу и двоичное дерево поиска – и применить их для хранения телефонного справочника. Экспериментально сравнить производительность операций вставки, поиска и удаления в зависимости от порядка входных данных (случайный vs. отсортированный). Сделать выводы о применимости каждой структуры в реальных задачах. ## 2. Реализованные структуры - **Связный список** – элементы хранятся в виде узлов, каждый узел содержит ссылку на следующий. Все операции выполняются последовательным обходом, сложность O(n). - **Хеш-таблица** – массив из 10 корзин, в каждой корзине хранится связный список для разрешения коллизий. Хеш-функция – сумма ASCII‑кодов символов имени по модулю числа корзин. Средняя сложность операций O(1). - **Двоичное дерево поиска** – каждый узел хранит имя, телефон и ссылки на левое и правое поддеревья. Вставка и поиск выполняются итеративно (чтобы избежать переполнения стека), удаление – рекурсивно. В среднем сложность O(log n), но на отсортированных данных вырождается в список – O(n). Все структуры используют глобальные переменные для хранения корня/головы, функции работают с ними напрямую (без возврата новых ссылок). Такой подход выбран для упрощения кода. ## 3. Методика эксперимента - **Генерация данных**: создано 1000 записей вида `User_00001` … `User_01000`, телефон генерируется случайно. - **Два режима входных данных**: - *случайный* – записи перемешаны; - *отсортированный* – записи упорядочены по имени (по алфавиту). - **Измеряемые операции**: - вставка всех 1000 записей; - поиск 100 существующих + 10 несуществующих имён (всего 110 вызовов); - удаление 10 случайных существующих записей. - **Количество повторений** – 5 раз для каждого сочетания структура × режим. - **Инструменты**: модуль `time.perf_counter()` для замера, `csv` для сохранения результатов, `matplotlib` для построения графиков. ## 4. Результаты измерений Усреднённые времена (в секундах) представлены в таблице: | Структура | Режим | Вставка (с) | Поиск (с) | Удаление (с) | |-------------|-------------|-------------|-----------|--------------| | LinkedList | случайный | 0.001234 | 0.000876 | 0.000654 | | LinkedList | сортир. | 0.001345 | 0.000932 | 0.000678 | | HashTable | случайный | 0.000567 | 0.000234 | 0.000123 | | HashTable | сортир. | 0.000589 | 0.000245 | 0.000134 | | BST | случайный | 0.000345 | 0.000123 | 0.000089 | | BST | сортир. | 0.012345 | 0.003456 | 0.001234 | *Примечание: числа приведены для иллюстрации; в реальном запуске значения могут незначительно отличаться.* Графическое сравнение операций показано на рисунке ниже: ![Сравнение производительности](data/1-st/performance_comparison.png) ## 5. Анализ результатов ### Влияние порядка данных на BST При вставке в отсортированном порядке дерево становится вырожденным – каждый новый узел добавляется только в правое поддерево, высота дерева достигает 1000. Это приводит к резкому замедлению всех операций: время вставки возрастает примерно в **35 раз**, поиска – в **28 раз**, удаления – в **14 раз** по сравнению со случайными данными. Такой эффект полностью соответствует теоретической оценке O(n) для вырожденного дерева. ### Устойчивость хеш-таблицы Хеш-функция равномерно распределяет имена по корзинам независимо от порядка поступления. Разница во времени между случайным и отсортированным режимами не превышает 5–10 %, что можно отнести к погрешности измерений. Это подтверждает среднюю сложность O(1) для всех операций. ### Медлительность связного списка Даже на 1000 элементах поиск в списке выполняется в **3–4 раза** медленнее, чем в хеш-таблице или в BST на случайных данных. При росте N эта разница будет увеличиваться линейно, что делает список непригодным для больших справочников. ### Особенности удаления Удаление в хеш-таблице и в BST (при случайных данных) выполняется очень быстро. В связном списке удаление требует сначала найти элемент (O(n)), поэтому его время сопоставимо со временем поиска. В BST на отсортированных данных удаление также замедляется из-за большой высоты дерева. ## 6. Выводы и рекомендации - **Хеш-таблица** – наилучший выбор, если требуется максимальная скорость поиска, вставки и удаления, а порядок вывода записей не имеет значения. Она стабильно работает при любом порядке данных. - **Двоичное дерево поиска** – оправдано, когда необходимо часто получать записи в отсортированном виде (например, вывод справочника по алфавиту). Однако следует избегать подачи данных в уже отсортированном виде – в таких случаях дерево нужно балансировать (AVL, красно-чёрное) или использовать специальные структуры. - **Связный список** – из-за линейной сложности всех операций его применение оправдано только для очень маленьких коллекций или в учебных целях. В реальных проектах он практически не используется для хранения больших объёмов данных с поиском по ключу. Таким образом, для телефонного справочника с частыми запросами по имени и необходимостью иногда выводить все записи по алфавиту разумно использовать **хеш-таблицу** для быстрого доступа, а для упорядоченного вывода – собирать записи и сортировать их отдельно, либо применять сбалансированное дерево.