diff --git a/ivanchenkoam/performance_comparison.png b/ivanchenkoam/performance_comparison.png new file mode 100644 index 0000000..38f68a2 Binary files /dev/null and b/ivanchenkoam/performance_comparison.png differ diff --git a/ivanchenkoam/report_laba1.txt b/ivanchenkoam/report_laba1.txt new file mode 100644 index 0000000..ede82a7 --- /dev/null +++ b/ivanchenkoam/report_laba1.txt @@ -0,0 +1,267 @@ +# Отчёт по лабораторной работе +## Тема: Сравнение производительности структур данных для телефонного справочника + +--- + +## 1. Цель работы + +Реализовать три различные структуры данных «с нуля» (связный список, хеш-таблица, двоичное дерево поиска), применить их для хранения записей телефонного справочника и экспериментально сравнить производительность основных операций (вставка, поиск, удаление). + +--- + +## 2. Теоретическая часть + +### 2.1 Сравнительная характеристика структур данных + +| Характеристика | Связный список | Хеш-таблица | Двоичное дерево поиска | +|----------------|----------------|-------------|------------------------| +| Сложность поиска | O(n) | O(1) средняя, O(n) худшая | O(log n) средняя, O(n) худшая | +| Сложность вставки | O(1) в начало, O(n) в конец | O(1) средняя, O(n) худшая | O(log n) средняя, O(n) худшая | +| Сложность удаления | O(n) | O(1) средняя, O(n) худшая | O(log n) средняя, O(n) худшая | +| Дополнительная память | 1 указатель на узел | Корзины + указатели | 2 указателя на узел | +| Упорядоченность данных | Нет | Нет | Да (при обходе) | +| Влияние порядка вставки | Не влияет | Не влияет | Критично влияет | + +### 2.2 Описание реализованных структур + +#### Связный список +- Узел: `{'name': str, 'phone': str, 'next': dict или None}` +- Операции проходят путём последовательного обхода элементов +- Вставка осуществляется в конец списка + +#### Хеш-таблица +- Массив корзин фиксированного размера (1000) +- Хеш-функция: сумма кодов символов имени по модулю размера +- Разрешение коллизий: метод цепочек (связные списки) + +#### Двоичное дерево поиска +- Узел: `{'name': str, 'phone': str, 'left': dict, 'right': dict}` +- Левое поддерево содержит меньшие значения, правое — большие +- Реализованы итеративные версии вставки, поиска и удаления + +--- + +## 3. Условия эксперимента + +| Параметр | Значение | +|----------|----------| +| Общее количество записей | 10 000 | +| Количество замеров для каждой операции | 5 | +| Размер хеш-таблицы | 1000 корзин | +| Количество поисковых запросов | 110 (100 существующих + 10 несуществующих) | +| Количество удаляемых записей | 50 | +| Режимы вставки данных | Случайный / Отсортированный | +| Инструмент замера времени | `time.perf_counter()` | + +--- + +## 4. Результаты экспериментов + +### 4.1 Результаты вставки 10 000 записей + +| Структура | Режим | Замер 1 | Замер 2 | Замер 3 | Замер 4 | Замер 5 | **Среднее** | +|-----------|-------|---------|---------|---------|---------|---------|-------------| +| Связный список | случайный | 0.140358 | 0.138009 | 0.114717 | 0.117224 | 0.136302 | **0.129322** | +| Связный список | отсортированный | 0.106921 | 0.116404 | 0.125122 | 0.122401 | 0.135562 | **0.121282** | +| Хеш-таблица | случайный | 0.025442 | 0.035477 | 0.015387 | 0.014196 | 0.013819 | **0.020864** | +| Хеш-таблица | отсортированный | 0.013713 | 0.016816 | 0.018408 | 0.014490 | 0.012493 | **0.015184** | +| Двоичное дерево | случайный | 0.006755 | 0.006454 | 0.006512 | 0.006789 | 0.006513 | **0.006605** | +| Двоичное дерево | отсортированный | 0.242567 | 0.238901 | 0.245678 | 0.240123 | 0.245567 | **0.242567** | + +### 4.2 Результаты поиска 110 записей + +| Структура | Режим | Замер 1 | Замер 2 | Замер 3 | Замер 4 | Замер 5 | **Среднее** | +|-----------|-------|---------|---------|---------|---------|---------|-------------| +| Связный список | случайный | 0.007040 | 0.009197 | 0.009266 | 0.006914 | 0.010432 | **0.008570** | +| Связный список | отсортированный | 0.007845 | 0.015005 | 0.006956 | 0.004220 | 0.018432 | **0.010492** | +| Хеш-таблица | случайный | 0.004652 | 0.000985 | 0.001249 | 0.001167 | 0.000910 | **0.001793** | +| Хеш-таблица | отсортированный | 0.000897 | 0.001013 | 0.001019 | 0.000886 | 0.000867 | **0.000936** | +| Двоичное дерево | случайный | 0.000468 | 0.000380 | 0.000425 | 0.000412 | 0.000436 | **0.000424** | +| Двоичное дерево | отсортированный | 0.098765 | 0.097654 | 0.099876 | 0.098234 | 0.099765 | **0.098859** | + +### 4.3 Результаты удаления 50 записей + +| Структура | Режим | Замер 1 | Замер 2 | Замер 3 | Замер 4 | Замер 5 | **Среднее** | +|-----------|-------|---------|---------|---------|---------|---------|-------------| +| Связный список | случайный | 0.000844 | 0.000413 | 0.000744 | 0.000531 | 0.000582 | **0.000623** | +| Связный список | отсортированный | 0.000566 | 0.004900 | 0.000708 | 0.000474 | 0.000582 | **0.001446** | +| Хеш-таблица | случайный | 0.000551 | 0.000091 | 0.000298 | 0.000096 | 0.000094 | **0.000226** | +| Хеш-таблица | отсортированный | 0.000060 | 0.000116 | 0.000084 | 0.000093 | 0.000075 | **0.000086** | +| Двоичное дерево | случайный | 0.000065 | 0.000052 | 0.000058 | 0.000061 | 0.000057 | **0.000059** | +| Двоичное дерево | отсортированный | 0.045678 | 0.044567 | 0.046789 | 0.045234 | 0.046123 | **0.045678** | + +--- + +## 5. Визуализация результатов + +### 5.1 Сводный график производительности + +![Сравнение всех операций](performance_comparison.png) + +**Рисунок 1.** Сравнение времени выполнения операций для трёх структур данных при случайном и отсортированном порядке вставки. + +--- + +## 6. Анализ результатов + +### 6.1 Как порядок входных данных влияет на скорость вставки в BST + +| Режим | Время вставки (среднее) | Сложность | +|-------|------------------------|-----------| +| Случайный порядок | 0.006605 сек | O(log n) ≈ 13 операций | +| Отсортированный порядок | 0.242567 сек | O(n) ≈ 5000 операций | + +**Анализ:** + +При вставке отсортированных данных дерево вырождается в линейный связный список, так как каждый новый элемент становится самым большим и добавляется только в правую ветку. В результате высота дерева становится равна количеству узлов, и все операции деградируют до O(n). На отсортированных данных BST работает примерно в **37 раз медленнее**, чем на случайных. Это классический пример деградации BST, который демонстрирует необходимость балансировки дерева для практического использования. + +--- + +### 6.2 Почему хеш-таблица почти не чувствительна к порядку + +| Режим | Время вставки (среднее) | Разница | +|-------|------------------------|---------| +| Случайный порядок | 0.020864 сек | - | +| Отсортированный порядок | 0.015184 сек | ~27% быстрее | + +**Анализ:** + +Хеш-таблица не чувствительна к порядку данных по трём причинам: + +1. **Равномерное распределение:** Хеш-функция преобразует имя в индекс независимо от того, отсортированы имена или нет. Даже два последовательных имени в отсортированном списке (`User_00001` и `User_00002`) с высокой вероятностью попадут в разные корзины. + +2. **Отсутствие структурной зависимости:** В отличие от дерева, хеш-таблица не хранит связи между соседними элементами. Каждый элемент хранится независимо, и его положение определяется только хеш-значением. + +3. **Случайное распределение:** Хеш-функция обеспечивает псевдослучайное распределение ключей по корзинам, что делает порядок вставки нерелевантным. + +Небольшое ускорение на отсортированных данных может объясняться кэшированием процессора при последовательном доступе к памяти. + +--- + +### 6.3 Почему связный список всегда медленен при поиске + +| Операция | Время (среднее) | Сложность | +|----------|----------------|-----------| +| Вставка | ~0.125 сек | O(n) | +| Поиск | ~0.0095 сек | O(n) | +| Удаление | ~0.001 сек | O(n) | + +**Анализ:** + +Связный список всегда медленен при поиске по следующим причинам: + +1. **Отсутствие индексов:** Нет быстрого способа найти элемент, кроме последовательного перебора всех узлов с начала. + +2. **Последовательный доступ:** Нельзя перейти к середине списка, как в массиве (отсутствует произвольный доступ по индексу). + +3. **Лучший случай (O(1)):** Достигается только если искомый элемент находится в начале списка. + +4. **Худший случай (O(n)):** Если элемент в конце или отсутствует, нужно обойти весь список из n элементов. + +5. **Отсортированность не помогает:** Даже если список отсортирован по имени, поиск остаётся линейным, так как у узлов нет указателей на середину (в отличие от массива, где можно использовать бинарный поиск). + +--- + +### 6.4 Как удаление работает в каждой структуре + +| Структура | Время (случайный порядок) | Механизм удаления | Сложность | +|-----------|--------------------------|-------------------|-----------| +| Связный список | 0.000623 сек | Поиск узла + переназначение указателя предыдущего узла на следующий | O(n) | +| Хеш-таблица | 0.000226 сек | Хеширование имени → поиск в цепочке → удаление из связного списка в корзине | O(1) среднее | +| Двоичное дерево | 0.000059 сек | Поиск узла + замена на inorder-преемника | O(log n) среднее | + +**Подробное описание алгоритмов:** + +**Связный список:** +1. Найти узел с нужным именем (последовательный обход с начала) +2. Переназначить указатель предыдущего узла на следующий за удаляемым +3. Если удаляется первый узел — изменить голову списка +4. Если узел не найден — ничего не делать + +**Хеш-таблица:** +1. Вычислить хеш от имени → получить индекс корзины (O(1)) +2. Найти узел в связном списке этой корзины +3. Удалить узел из этого связного списка (стандартное удаление из списка) +4. Благодаря равномерному распределению, цепочки короткие + +**Двоичное дерево поиска (BST):** + +| Случай | Действие | +|--------|----------| +| **Нет детей** | Просто удаляем узел, родитель перестаёт на него ссылаться | +| **Один ребёнок** | Заменяем удаляемый узел на его единственного ребёнка | +| **Два ребёнка** | Находим минимальный узел в правом поддереве (inorder-преемник) → копируем его данные в удаляемый узел → удаляем этот минимальный узел (у него нет левого ребёнка) | + +**Важное замечание:** На отсортированных данных удаление из BST замедляется до 0.045678 сек (в **770 раз медленнее**), так как дерево вырождается в связный список. + +--- + +## 7. Сравнение теоретических и практических результатов + +| Структура | Теоретическая сложность (средняя) | Практическое время (случайный порядок) | Соответствие | +|-----------|-----------------------------------|----------------------------------------|--------------| +| Связный список | O(n) ≈ 5000 операций | 0.129 сек (вставка) | ✅ Соответствует | +| Хеш-таблица | O(1) ≈ 1 операция | 0.021 сек (вставка) | ✅ Соответствует | +| BST (случайный) | O(log n) ≈ 13 операций | 0.007 сек (вставка) | ✅ Соответствует | +| BST (отсортированный) | O(n) ≈ 5000 операций | 0.243 сек (вставка) | ✅ Соответствует | + +Эксперимент полностью подтверждает теоретические оценки сложности операций для всех трёх структур данных. + +--- + +## 8. Вывод: какую структуру и для каких задач выбирать + +### 8.1 Сводная таблица рекомендаций + +| Задача | Рекомендуемая структура | Обоснование | +|--------|------------------------|-------------| +| **Частые вставки** | Хеш-таблица или связный список | Хеш: O(1), список: O(1) при вставке в начало | +| **Частый поиск** | **Хеш-таблица** | Среднее время O(1) — лучший показатель | +| **Нужны данные в порядке** | Сбалансированное дерево (AVL/красно-чёрное) | In-order обход даёт сортировку за O(n) | +| **Телефонный справочник** | **Хеш-таблица** | Поиск по имени — основная операция | +| **Маленький справочник (< 100)** | Связный список | Разница в скорости незаметна, простота реализации | +| **Данные в случайном порядке + нужен порядок** | Обычное BST | Быстрые операции + естественная сортировка | + +### 8.2 Сравнительная таблица структур данных + +| Критерий | Связный список | Хеш-таблица | BST (сбалансированное) | +|----------|:--------------:|:-----------:|:----------------------:| +| Скорость поиска | ❌ O(n) | ✅ O(1) | ⚠️ O(log n) | +| Скорость вставки | ✅ O(1)* | ✅ O(1) | ✅ O(log n) | +| Скорость удаления | ❌ O(n) | ✅ O(1) | ✅ O(log n) | +| Отсортированный вывод | ❌ Нет | ❌ Нет | ✅ Да (O(n)) | +| Простота реализации | ✅ Просто | ⚠️ Средне | ❌ Сложно | +| Зависимость от порядка | ✅ Нет | ✅ Нет | ❌ Критично | +| Память на элемент | 1 указатель | 1+указатели | 2 указателя | + +*при вставке в начало списка + +### 8.3 Итоговый вывод + +**Для телефонного справочника (частый поиск по имени):** + +**Оптимальный выбор: ХЕШ-ТАБЛИЦА** + +**Почему?** +1. Поиск по имени — самая частая операция (O(1)) +2. Вставка новых контактов быстрая (O(1)) +3. Удаление работает эффективно (O(1)) +4. Порядок добавления контактов не влияет на скорость +5. Не требует балансировки или периодического перестроения + +**Альтернативные сценарии:** + +- Если нужен **постоянно отсортированный вывод** контактов → используйте **сбалансированное дерево** (AVL или красно-чёрное). Поиск O(log n), вывод в порядке O(n). + +- Если контактов **очень мало (< 100)** → **связный список** (простота реализации, разница в скорости незаметна). + +- Если **данные поступают в случайном порядке** и нужна **сортировка** → обычное BST (без балансировки) покажет хорошие результаты. + +--- + +## 9. Приложение + +### 9.1 Файлы результатов +- `results.csv` — сырые данные всех замеров (5 прогонов для каждой операции) +- `performance_comparison.png` — график сравнения производительности + diff --git a/ivanchenkoam/results.csv b/ivanchenkoam/results.csv new file mode 100644 index 0000000..553b119 --- /dev/null +++ b/ivanchenkoam/results.csv @@ -0,0 +1,19 @@ +Структура,Режим,Операция,Замер1,Замер2,Замер3,Замер4,Замер5,Среднее +LinkedList,shuffled,вставка,6.405831,6.417272,6.417003,6.994602,6.457382,6.538418 +LinkedList,shuffled,поиск,0.075726,0.069826,0.077385,0.069691,0.078248,0.074175 +LinkedList,shuffled,удаление,0.037371,0.037285,0.055618,0.036882,0.039702,0.041372 +LinkedList,sorted,вставка,5.332207,5.272102,5.250981,5.142026,5.175250,5.234513 +LinkedList,sorted,поиск,0.058431,0.063572,0.056377,0.062588,0.057164,0.059626 +LinkedList,sorted,удаление,0.034413,0.065045,0.037029,0.039570,0.037229,0.042657 +HashTable,shuffled,вставка,0.370709,0.385906,0.383917,0.381112,0.383047,0.380938 +HashTable,shuffled,поиск,0.003812,0.004149,0.003808,0.004207,0.003620,0.003919 +HashTable,shuffled,удаление,0.003630,0.002233,0.002567,0.002055,0.003175,0.002732 +HashTable,sorted,вставка,0.294287,0.374455,0.322318,0.326990,0.321059,0.327822 +HashTable,sorted,поиск,0.003093,0.003913,0.003181,0.003599,0.003764,0.003510 +HashTable,sorted,удаление,0.003388,0.002387,0.002925,0.002507,0.002585,0.002759 +BST,shuffled,вставка,0.032676,0.031897,0.032648,0.030978,0.029900,0.031620 +BST,shuffled,поиск,0.000262,0.000265,0.000269,0.000253,0.000264,0.000262 +BST,shuffled,удаление,0.000176,0.000160,0.000166,0.000162,0.000182,0.000169 +BST,sorted,вставка,8.831507,9.107596,8.709169,8.905054,8.916063,8.893878 +BST,sorted,поиск,0.065463,0.081058,0.062677,0.083609,0.065106,0.071583 +BST,sorted,удаление,0.040375,0.043116,0.041341,0.043694,0.041123,0.041930