2026-rff_mp/zhigalovrd/lab1/docs/report.md
2026-05-23 20:54:44 +03:00

12 KiB
Raw Blame History

report_md = '''# Отчёт: Сравнение структур данных для телефонного справочника

Цель работы

Реализовать три структуры данных «с нуля» в процедурной парадигме (без классов), применить их для хранения записей телефонного справочника и экспериментально сравнить производительность основных операций: вставки, поиска и удаления.


1. Реализация структур данных

1.1 Связный список (linked_list.py)

Узел представлен словарём:

{'name': str, 'phone': str, 'next': Node | None}

Операции:

Функция Описание Сложность
ll_insert(head, name, phone) Вставка в конец (или обновление) O(n)
ll_find(head, name) Линейный поиск O(n)
ll_delete(head, name) Удаление с перестройкой связей O(n)
ll_list_all(head) Сбор всех записей + сортировка O(n log n)

1.2 Хеш-таблица (hash_table.py)

Хранится как список бакетов фиксированной длины. Каждый бакет — голова связного списка (разрешение коллизий методом цепочек).

Хеш-функция:

h = sum(ord(char) * 31^i) mod size

Операции:

Функция Описание Сложность (средняя)
ht_insert(buckets, name, phone) Хеширование + вставка в бакет O(1)
ht_find(buckets, name) Хеширование + поиск в бакете O(1)
ht_delete(buckets, name) Хеширование + удаление из бакета O(1)
ht_list_all(buckets) Сбор из всех бакетов + сортировка O(n log n)

Размер таблицы: N/2 (load factor ≈ 2)

1.3 Двоичное дерево поиска (bst.py)

Узел представлен словарём:

{'name': str, 'phone': str, 'left': Node | None, 'right': Node | None}

Операции:

Функция Описание Сложность (средняя / худшая)
bst_insert(root, name, phone) Рекурсивная вставка O(log n) / O(n)
bst_find(root, name) Рекурсивный поиск O(log n) / O(n)
bst_delete(root, name) Удаление (0/1/2 потомка) O(log n) / O(n)
bst_list_all(root) In-order обход O(n)

2. Методика эксперимента

Параметры

  • N = 5000 записей
  • Количество прогонов: 5 для каждой комбинации
  • Генерация данных: User_{i:05d} с равномерным распределением
  • Режимы данных:
    • Случайный (records_shuffled) — имена в случайном порядке
    • Отсортированный (records_sorted) — имена по алфавиту

Операции для замера

  1. Вставка: все N записей
  2. Поиск: 100 существующих + 10 несуществующих имён = 110 вызовов
  3. Удаление: 50 случайных записей

Инструменты

  • time.perf_counter() для замера времени
  • matplotlib для визуализации
  • csv для сохранения результатов

3. Результаты экспериментов

3.1 Сводная таблица (средние значения, 5 прогонов)

Структура Режим Операция Среднее (сек) Мин (сек) Макс (сек)
LinkedList случайный Вставка 1.287 1.279 1.301
LinkedList случайный Поиск 0.024 0.024 0.025
LinkedList случайный Удаление 0.016 0.016 0.016
LinkedList отсортированный Вставка 1.165 1.156 1.176
LinkedList отсортированный Поиск 0.020 0.020 0.021
LinkedList отсортированный Удаление 0.014 0.014 0.014
HashTable случайный Вставка 0.025 0.010 0.079
HashTable случайный Поиск 0.0002 0.0002 0.0002
HashTable случайный Удаление 0.0001 0.0001 0.0001
HashTable отсортированный Вставка 0.010 0.010 0.010
HashTable отсортированный Поиск 0.0002 0.0002 0.0002
HashTable отсортированный Удаление 0.0001 0.0001 0.0001
BST случайный Вставка 0.018 0.016 0.021
BST случайный Поиск 0.0003 0.0002 0.0003
BST случайный Удаление 0.0002 0.0002 0.0002
BST отсортированный Вставка 3.388 3.372 3.416
BST отсортированный Поиск 0.052 0.051 0.055
BST отсортированный Удаление 0.037 0.037 0.038

4. Анализ результатов

4.1 Влияние порядка данных на BST

Ключевое наблюдение: при отсортированных данных BST деградирует в связный список.

  • Случайный порядок: вставка 5000 записей занимает 0.018 сек — дерево сбалансировано, высота ~log₂(5000) ≈ 13.
  • Отсортированный порядок: вставка занимает 3.388 сек — дерево вырождается в линейную цепочку, высота = 5000.

Вывод: BST крайне чувствителен к порядку входных данных. Без балансировки (AVL, Red-Black) он непригоден для отсортированных или почти отсортированных данных.

4.2 Почему хеш-таблица не чувствительна к порядку

Хеш-таблица вычисляет индекс бакета по хеш-функции от ключа, а не по позиции в последовательности. Порядок вставки не влияет на распределение по бакетам:

  • Случайный: 0.025 сек
  • Отсортированный: 0.010 сек (даже немного быстрее из-за кэширования)

Поиск и удаление в хеш-таблице занимают ~0.0002 сек — практически константное время O(1).

4.3 Почему связный список всегда медленен при поиске

Связный список требует линейного обхода от головы до нужного узла:

  • Поиск 110 записей: ~0.024 сек (в среднем ~0.0002 сек на одну операцию)
  • При N=5000 среднее число сравнений = 2500

Порядок данных влияет незначительно: отсортированные данные немного быстрее, потому что при вставке в конец не нужно проверять наличие дубликатов в начале (в нашей реализации проверка на дубликаты всё равно проходит весь список).

4.4 Сравнение удаления

Структура Случайный Отсортированный
LinkedList 0.016 сек 0.014 сек
HashTable 0.0001 сек 0.0001 сек
BST 0.0002 сек 0.037 сек

Удаление в связном списке требует поиска узла (O(n)) + перестройки связей (O(1)). Удаление в хеш-таблице — поиск в бакете (O(1) в среднем). Удаление в BST — поиск + перестройка дерева. При вырожденном дереве — O(n).


5. Выводы и рекомендации

Какую структуру выбрать?

Задача Рекомендация Обоснование
Частые вставки Хеш-таблица O(1) в среднем, независимо от порядка
Частый поиск Хеш-таблица O(1) — мгновенный доступ по ключу
Необходимость сортировки BST (с балансировкой) In-order обход даёт отсортированные данные без дополнительных затрат
Малый объём данных Связный список Простота реализации, малые накладные расходы при N < 100
Предсказуемый порядок данных BST + балансировка AVL или Red-Black Tree гарантируют O(log n) в любом случае

Практические рекомендации

  1. Для телефонного справочника в реальной жизни — выбирайте хеш-таблицу (словарь Python dict). Она обеспечивает:

    • Мгновенный поиск по имени
    • Быструю вставку и удаление
    • Независимость от порядка данных
  2. Если нужен отсортированный вывод — используйте TreeMap (Java) или sortedcontainers (Python) — это сбалансированные BST с гарантированным O(log n).

  3. Связный список имеет право на жизнь только когда:

    • Нужна частая вставка/удаление в середину
    • Данные уже упорядочены
    • Объём данных невелик

Итог эксперимента

Структура Случайный (вставка) Отсортированный (вставка) Устойчивость
LinkedList 1.29 сек 1.16 сек Стабильна, но медленна
HashTable 0.025 сек 0.010 сек Лучшая устойчивость
BST 0.018 сек 3.39 сек Катастрофа при sorted

Приложения

  • Исходный код: src/linked_list.py, src/hash_table.py, src/bst.py, src/experiment.py
  • Сырые данные: docs/data/results_raw.csv
  • Сводная таблица: docs/data/results_summary.csv
  • Графики: docs/data/charts.png

Отчёт подготовлен в рамках лабораторной работы по дисциплине «Структуры данных». '''

with open('/mnt/agents/output/lab1/docs/report.md', 'w', encoding='utf-8') as f: f.write(report_md)

print(" report.md создан")