[1] отчет по лабе 1

This commit is contained in:
ivanchenkoam 2026-05-23 17:17:23 +03:00
parent 07effa49c2
commit 6fc7a657d2
3 changed files with 286 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -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` — график сравнения производительности

19
ivanchenkoam/results.csv Normal file
View File

@ -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
1 Структура Режим Операция Замер1 Замер2 Замер3 Замер4 Замер5 Среднее
2 LinkedList shuffled вставка 6.405831 6.417272 6.417003 6.994602 6.457382 6.538418
3 LinkedList shuffled поиск 0.075726 0.069826 0.077385 0.069691 0.078248 0.074175
4 LinkedList shuffled удаление 0.037371 0.037285 0.055618 0.036882 0.039702 0.041372
5 LinkedList sorted вставка 5.332207 5.272102 5.250981 5.142026 5.175250 5.234513
6 LinkedList sorted поиск 0.058431 0.063572 0.056377 0.062588 0.057164 0.059626
7 LinkedList sorted удаление 0.034413 0.065045 0.037029 0.039570 0.037229 0.042657
8 HashTable shuffled вставка 0.370709 0.385906 0.383917 0.381112 0.383047 0.380938
9 HashTable shuffled поиск 0.003812 0.004149 0.003808 0.004207 0.003620 0.003919
10 HashTable shuffled удаление 0.003630 0.002233 0.002567 0.002055 0.003175 0.002732
11 HashTable sorted вставка 0.294287 0.374455 0.322318 0.326990 0.321059 0.327822
12 HashTable sorted поиск 0.003093 0.003913 0.003181 0.003599 0.003764 0.003510
13 HashTable sorted удаление 0.003388 0.002387 0.002925 0.002507 0.002585 0.002759
14 BST shuffled вставка 0.032676 0.031897 0.032648 0.030978 0.029900 0.031620
15 BST shuffled поиск 0.000262 0.000265 0.000269 0.000253 0.000264 0.000262
16 BST shuffled удаление 0.000176 0.000160 0.000166 0.000162 0.000182 0.000169
17 BST sorted вставка 8.831507 9.107596 8.709169 8.905054 8.916063 8.893878
18 BST sorted поиск 0.065463 0.081058 0.062677 0.083609 0.065106 0.071583
19 BST sorted удаление 0.040375 0.043116 0.041341 0.043694 0.041123 0.041930