{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "7cbca316", "metadata": {}, "outputs": [], "source": [ "{\n", " \"cells\": [\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"id\": \"start\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"# Отчёт по лабораторной работе\\n\",\n", " \"## Тема: Сравнение производительности структур данных для телефонного справочника\\n\",\n", " \"\\n\",\n", " \"---\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"id\": \"goal\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"## 1. Цель работы\\n\",\n", " \"\\n\",\n", " \"Реализовать три различные структуры данных «с нуля», применить их для хранения записей телефонного справочника и экспериментально сравнить производительность основных операций (вставка, поиск, удаление).\\n\",\n", " \"\\n\",\n", " \"---\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"id\": \"conditions\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"## 2. Условия эксперимента\\n\",\n", " \"\\n\",\n", " \"| Параметр | Значение |\\n\",\n", " \"|----------|----------|\\n\",\n", " \"| Общее число записей | 10 000 |\\n\",\n", " \"| Каждый замер повторялся | 5 раз |\\n\",\n", " \"| Количество существующих записей для поиска | 100 |\\n\",\n", " \"| Количество несуществующих записей для поиска | 10 |\\n\",\n", " \"| Количество элементов для удаления | 50 |\\n\",\n", " \"| Размер хеш-таблицы | 2003 (простое число) |\\n\",\n", " \"| Режимы тестирования | Случайный / Отсортированный |\\n\",\n", " \"\\n\",\n", " \"---\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"id\": \"graphs\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"## 3. Практические графики\\n\",\n", " \"\\n\",\n", " \"### Информация о тестировании\\n\",\n", " \"- Общее число записей: 10 000\\n\",\n", " \"- Каждый замер повторялся: 5 раз\\n\",\n", " \"- Количество существующих записей для случайного поиска: 100\\n\",\n", " \"- Количество несуществующих записей для поиска: 10\\n\",\n", " \"- Количество элементов для удаления: 50\\n\",\n", " \"\\n\",\n", " \"![График вставки](graphs.png)\\n\",\n", " \"\\n\",\n", " \"**Рис. 1 – Тестирование вставки (логарифмическая шкала)**\\n\",\n", " \"\\n\",\n", " \"---\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"id\": \"analysis_bst\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"## 4. Анализ результатов\\n\",\n", " \"\\n\",\n", " \"### Как порядок входных данных влияет на скорость вставки в BST (деградация до O(n) на отсортированных данных)?\\n\",\n", " \"\\n\",\n", " \"По определению, при вставке отсортированных данных, структура бинарного дерева поиска вырождается в связный список.\\n\",\n", " \"\\n\",\n", " \"**Результаты тестирования:**\\n\",\n", " \"- На случайных данных: время вставки ~0.037 секунд\\n\",\n", " \"- На отсортированных данных: время вставки ~18.34 секунд (деградация в ~470 раз!)\\n\",\n", " \"\\n\",\n", " \"Заметим, что при случайных данных скорость вставки в бинарное дерево почти лишь немного уступает по скорости хеш-таблице. При отсортированных данных дерево фактически превращается в связный список, и из-за рекурсивной реализации вставки бинарное дерево становится даже медленнее связного списка.\\n\",\n", " \"\\n\",\n", " \"---\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"id\": \"analysis_hash\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"### Почему хеш-таблица почти не чувствительна к порядку?\\n\",\n", " \"\\n\",\n", " \"Хеш-таблица не чувствительна к порядку данных, так как:\\n\",\n", " \"1. Использует для распределения элементов хеш-значения данных (сложность операции одинакова для любых однотипных данных)\\n\",\n", " \"2. Хеш-функция равномерно распределяет ключи по корзинам независимо от их порядка\\n\",\n", " \"3. Вставка в конкретную корзину не зависит от соседних элементов\\n\",\n", " \"\\n\",\n", " \"**Экспериментальное подтверждение:**\\n\",\n", " \"- Случайный порядок: вставка = 0.0369 сек, поиск = 0.000355 сек\\n\",\n", " \"- Отсортированный порядок: вставка = 0.0356 сек, поиск = 0.000380 сек\\n\",\n", " \"\\n\",\n", " \"Разница незначительна и находится в пределах погрешности измерений.\\n\",\n", " \"\\n\",\n", " \"---\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"id\": \"analysis_list\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"### Почему связный список всегда медленен при поиске?\\n\",\n", " \"\\n\",\n", " \"Операция поиска в связном списке имеет линейную сложность **O(n)** независимо от порядка данных, так как:\\n\",\n", " \"- Нет индексов для прямого доступа\\n\",\n", " \"- Нет сортировки, позволяющей применять бинарный поиск\\n\",\n", " \"- Приходится последовательно перебирать все элементы до найденного\\n\",\n", " \"\\n\",\n", " \"| Структура | Сложность поиска | Время поиска (случайный) |\\n\",\n", " \"|-----------|-----------------|--------------------------|\\n\",\n", " \"| Связный список | O(n) | 0.0427 сек |\\n\",\n", " \"| Хеш-таблица | O(1) средняя | 0.000355 сек |\\n\",\n", " \"| BST (случайный) | O(log n) | 0.000527 сек |\\n\",\n", " \"\\n\",\n", " \"---\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"id\": \"analysis_delete\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"### Как удаление работает в каждой структуре?\\n\",\n", " \"\\n\",\n", " \"#### Связный список\\n\",\n", " \"Находим элемент перед удаляемым элементом и заменяем его поле `next` на `next.next`:\\n\",\n", " \"```python\\n\",\n", " \"current = head\\n\",\n", " \"while current['next'] is not None:\\n\",\n", " \" if current['next']['name'] == name:\\n\",\n", " \" current['next'] = current['next']['next']\\n\",\n", " \" return head\\n\",\n", " \" current = current['next']\\n\",\n", " \"```\\n\",\n", " \"\\n\",\n", " \"#### Двоичное дерево поиска\\n\",\n", " \"После того, как мы нашли узел, который необходимо удалить, возможны три случая:\\n\",\n", " \"\\n\",\n", " \"**Случай 1:** У удаляемого узла нет детей → просто удаляем узел.\\n\",\n", " \"\\n\",\n", " \"**Случай 2:** У удаляемого узла есть только один ребёнок → ребёнок занимает место удалённого узла.\\n\",\n", " \"\\n\",\n", " \"**Случай 3:** У удаляемого узла есть оба ребёнка → находим минимальный элемент в правом поддереве (самый левый узел) и заменяем им удаляемый узел.\\n\",\n", " \"\\n\",\n", " \"#### Хеш-таблица\\n\",\n", " \"1. Вычисляем хеш-индекс: `index = hash_func(name, len(buckets))`\\n\",\n", " \"2. Находим нужную корзину: `buckets[index]`\\n\",\n", " \"3. Удаляем элемент из связного списка в этой корзине\\n\",\n", " \"\\n\",\n", " \"**Сравнение времени удаления:**\\n\",\n", " \"\\n\",\n", " \"| Структура | Время удаления (случайный) | Сложность |\\n\",\n", " \"|-----------|---------------------------|-----------|\\n\",\n", " \"| Связный список | 0.0341 сек | O(n) |\\n\",\n", " \"| Хеш-таблица | 0.00018 сек | O(1) средняя |\\n\",\n", " \"| BST | 0.0793 сек | O(log n) средняя |\\n\",\n", " \"\\n\",\n", " \"---\"\n", " ]\n", " },\n", " {\n", " \"cell_type\": \"markdown\",\n", " \"id\": \"conclusion\",\n", " \"metadata\": {},\n", " \"source\": [\n", " \"## 5. Вывод\\n\",\n", " \"\\n\",\n", " \"Мы реализовали и протестировали три различные структуры хранения данных: связный список, хеш-таблицу и двоичное дерево поиска. Сравнили скорость операций вставки, удаления и поиска для каждой структуры.\\n\",\n", " \"\\n\",\n", " \"### Итоговая таблица производительности (случайный порядок):\\n\",\n", " \"\\n\",\n", " \"| Структура | Вставка (сек) | Поиск (сек) | Удаление (сек) |\\n\",\n", " \"|-----------|---------------|-------------|----------------|\\n\",\n", " \"| Связный список | 4.6031 | 0.0427 | 0.0341 |\\n\",\n", " \"| Хеш-таблица | **0.0369** | **0.00036** | **0.00018** |\\n\",\n", " \"| BST | 0.0369 | 0.00053 | 0.0793 |\\n\",\n", " \"\\n\",\n", " \"### Рекомендации по выбору структуры данных:\\n\",\n", " \"\\n\",\n", " \"1. **Хеш-таблица** – лучший выбор для телефонного справочника:\\n\",\n", " \" - Не важен порядок хранения и извлечения данных\\n\",\n", " \" - Требуется максимальная скорость поиска и вставки\\n\",\n", " \" - Результат: **победитель по всем параметрам**\\n\",\n", " \"\\n\",\n", " \"2. **Двоичное дерево поиска** – выбираем, если:\\n\",\n", " \" - Нужно хранить данные с возможностью быстрого отсортированного обхода\\n\",\n", " \" - Данные поступают в случайном порядке (иначе будет деградация)\\n\",\n", " \" - Можно использовать сбалансированную версию (AVL, красно-чёрное)\\n\",\n", " \"\\n\",\n", " \"3. **Связный список** – выбираем, если:\\n\",\n", " \" - Нужно хранить данные в порядке поступления (очередь, стек)\\n\",\n", " \" - Объём данных очень маленький (< 100 записей)\\n\",\n", " \" - Простота реализации важнее производительности\\n\",\n", " \"\\n\",\n", " \"---\\n\",\n", " \"\\n\",\n", " \"**Заключение:** Для реализации телефонного справочника оптимальнее всего использовать **хеш-таблицу**, так как она обеспечивает наилучшую производительность для всех операций и не чувствительна к порядку входных данных.\"\n", " ]\n", " }\n", " ],\n", " \"metadata\": {\n", " \"kernelspec\": {\n", " \"display_name\": \"Python 3\",\n", " \"language\": \"python\",\n", " \"name\": \"python3\"\n", " },\n", " \"language_info\": {\n", " \"name\": \"python\",\n", " \"version\": \"3.14.0\"\n", " }\n", " },\n", " \"nbformat\": 4,\n", " \"nbformat_minor\": 5\n", "}" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }