246 lines
14 KiB
Plaintext
246 lines
14 KiB
Plaintext
{
|
||
"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",
|
||
" \"\\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
|
||
}
|