2026-rff_mp/shahovaa/zadanie1/docs/report.md
2026-05-19 22:11:31 +03:00

7.4 KiB
Raw Blame History

Отчет по заданию 1: структуры данных

Цель

Реализовать три структуры данных с нуля в процедурной парадигме и сравнить скорость основных операций телефонного справочника:

  • insert(name, phone) - добавить или обновить запись;
  • find(name) - найти телефон по имени;
  • delete(name) - удалить запись;
  • list_all() - получить все записи, отсортированные по имени.

Классы не использовались. Узлы связного списка и дерева представлены словарями, хеш-таблица представлена списком бакетов.

Реализация

Код находится в файле phonebook.py.

Реализованы функции:

  • связный список: ll_insert, ll_find, ll_delete, ll_list_all;
  • хеш-таблица: create_hash_table, ht_insert, ht_find, ht_delete, ht_list_all;
  • двоичное дерево поиска: bst_insert, bst_find, bst_delete, bst_list_all.

Для хеш-таблицы используется метод цепочек: каждый бакет хранит голову связного списка. Хеш-функция написана вручную, чтобы результат не зависел от рандомизации встроенной функции hash() в Python.

Для BST вставка, поиск, удаление и обход написаны без классов. Обход bst_list_all реализован итеративно, чтобы отсортированный вход на 10000 элементов не приводил к переполнению стека рекурсии.

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

Скрипт эксперимента находится в файле benchmark.py.

Параметры запуска:

  • количество записей: N = 10000;
  • число повторов каждого эксперимента: 5;
  • имена: User_00000, User_00001, ..., User_09999;
  • два режима входных данных: shuffled и sorted;
  • поиск: 100 существующих имен и 10 отсутствующих;
  • удаление: 50 случайных существующих имен;
  • размер хеш-таблицы: 20011 бакетов.

После вставки структура не пересоздается: поиск и удаление выполняются на той же заполненной структуре. Для каждого режима и каждой структуры создается новая структура.

Файлы с результатами:

  • docs/data/results.csv - все отдельные замеры;
  • docs/data/summary.csv - среднее время и список всех пяти замеров;
  • docs/data/performance.svg - столбчатая диаграмма средних значений.

График производительности

Средние результаты

Время указано в секундах.

Структура Режим Вставка Поиск Удаление
LinkedList shuffled 1.555942 0.014180 0.006345
LinkedList sorted 1.513740 0.012993 0.006041
HashTable shuffled 0.005934 0.000056 0.000031
HashTable sorted 0.006140 0.000056 0.000029
BST shuffled 0.011223 0.000093 0.000069
BST sorted 2.250442 0.019857 0.010803

Анализ

Связный список оказался самым медленным на вставке и поиске. Причина в том, что для корректной операции insert нужно проверить, есть ли уже запись с таким именем. При уникальных именах почти каждая вставка проходит по всему текущему списку, поэтому суммарная сложность вставки всех записей становится O(n^2). Порядок входных данных почти не влияет на результат, потому что структура не использует порядок ключей.

Хеш-таблица показала лучшие результаты почти во всех операциях. При хорошем распределении по бакетам вставка, поиск и удаление близки к O(1). Порядок входных данных почти не влияет на время, так как индекс бакета определяется хешем имени, а не расположением записи во входном списке.

BST хорошо работает на перемешанных данных: дерево получается сравнительно сбалансированным, поэтому операции близки к O(log n). На отсортированном входе обычное двоичное дерево поиска вырождается в цепочку: каждый новый ключ становится правым потомком предыдущего. Из-за этого вставка всех записей становится O(n^2), а поиск и удаление приближаются к поведению связного списка.

Удаление у хеш-таблицы быстрое по той же причине, что и поиск: сначала вычисляется бакет, затем просматривается короткая цепочка. В BST удаление быстрое на перемешанном дереве, но на вырожденном дереве оно замедляется. В связном списке удаление требует линейного поиска удаляемого элемента.

Вывод

Для частого поиска, обновления и удаления по точному имени лучше выбирать хеш-таблицу. Она быстрее всего в эксперименте и почти не зависит от порядка вставки.

Если нужно часто получать данные в отсортированном порядке, дерево поиска дает удобный in-order обход без отдельной сортировки. Но обычный BST чувствителен к порядку входных данных, поэтому на практике лучше использовать самобалансирующееся дерево или готовую структуру из библиотеки.

Связный список подходит только для маленьких наборов данных или учебных задач. Для телефонного справочника с частым поиском он неудачен, потому что каждая операция поиска требует последовательного прохода по элементам.