diff --git a/src/bst.py b/src/bst.py deleted file mode 100644 index 04ba1d3..0000000 --- a/src/bst.py +++ /dev/null @@ -1,88 +0,0 @@ -# bst.py -# Двоичное дерево поиска по имени - -def create_node(name, phone): - """Создаёт узел дерева.""" - return { - 'name': name, - 'phone': phone, - 'left': None, - 'right': None - } - -def bst_insert(root, name, phone): - """ - Рекурсивно вставляет или обновляет запись. - Возвращает корень (может измениться при первой вставке). - """ - if root is None: - return create_node(name, phone) - - if name < root['name']: - root['left'] = bst_insert(root['left'], name, phone) - elif name > root['name']: - root['right'] = bst_insert(root['right'], name, phone) - else: # имя уже существует – обновляем телефон - root['phone'] = phone - return root - -def bst_find(root, name): - """Возвращает телефон или None.""" - if root is None: - return None - if name == root['name']: - return root['phone'] - elif name < root['name']: - return bst_find(root['left'], name) - else: - return bst_find(root['right'], name) - -def _min_node(node): - """Находит узел с минимальным именем в поддереве.""" - current = node - while current['left'] is not None: - current = current['left'] - return current - -def bst_delete(root, name): - """ - Удаляет узел с заданным именем. - Возвращает новый корень поддерева. - """ - if root is None: - return None - - if name < root['name']: - root['left'] = bst_delete(root['left'], name) - elif name > root['name']: - root['right'] = bst_delete(root['right'], name) - else: - # Узел найден - if root['left'] is None: - return root['right'] - elif root['right'] is None: - return root['left'] - - # Узел с двумя детьми: находим минимальный в правом поддереве - temp = _min_node(root['right']) - root['name'] = temp['name'] - root['phone'] = temp['phone'] - root['right'] = bst_delete(root['right'], temp['name']) - - return root - -def bst_list_all(root): - """ - Центрированный (in-order) обход – возвращает записи, - уже отсортированные по имени. - """ - def _inorder(node, result): - if node is None: - return - _inorder(node['left'], result) - result.append((node['name'], node['phone'])) - _inorder(node['right'], result) - - records = [] - _inorder(root, records) - return records \ No newline at end of file diff --git a/src/hash_table.py b/src/hash_table.py deleted file mode 100644 index 9f914f6..0000000 --- a/src/hash_table.py +++ /dev/null @@ -1,46 +0,0 @@ -# hash_table.py -# Хеш-таблица с цепочками (использует linked_list.py) - -import linked_list as ll - -def create_hash_table(size=1000): - """ - Создаёт пустую хеш-таблицу. - size – количество корзин (рекомендуется простое число). - """ - return [None] * size - -def _hash(name, table_size): - """Простая хеш-функция на основе суммы кодов символов.""" - return sum(ord(ch) for ch in name) % table_size - -def ht_insert(table, name, phone): - """Вставляет или обновляет запись.""" - idx = _hash(name, len(table)) - # Вставляем в связный список в этой корзине - table[idx] = ll.ll_insert(table[idx], name, phone) - -def ht_find(table, name): - """Ищет телефон по имени.""" - idx = _hash(name, len(table)) - return ll.ll_find(table[idx], name) - -def ht_delete(table, name): - """Удаляет запись по имени.""" - idx = _hash(name, len(table)) - table[idx] = ll.ll_delete(table[idx], name) - -def ht_list_all(table): - """ - Собирает все записи из всех корзин, - возвращает отсортированный по имени список. - """ - records = [] - for bucket in table: - # Каждая корзина – голова связного списка - current = bucket - while current is not None: - records.append((current['name'], current['phone'])) - current = current['next'] - records.sort(key=lambda x: x[0]) - return record \ No newline at end of file diff --git a/src/linked_list.py b/src/linked_list.py deleted file mode 100644 index fefab0b..0000000 --- a/src/linked_list.py +++ /dev/null @@ -1,74 +0,0 @@ -# linked_list.py -# Связный список для телефонного справочника - -def create_node(name, phone): - """Создаёт новый узел-словарь.""" - return {'name': name, 'phone': phone, 'next': None} - -def ll_insert(head, name, phone): - """ - Вставляет или обновляет запись. - Если имя уже существует – обновляет телефон. - Если нет – добавляет в конец списка. - Возвращает голову списка (может измениться, если вставка в начало). - """ - # Если список пуст – создаём первый узел - if head is None: - return create_node(name, phone) - - # Проверяем, не находится ли имя в первом узле - if head['name'] == name: - head['phone'] = phone - return head - - # Ищем узел с таким именем или конец списка - current = head - while current['next'] is not None: - if current['next']['name'] == name: - current['next']['phone'] = phone - return head - current = current['next'] - - # Имя не найдено – добавляем в конец - current['next'] = create_node(name, phone) - return head - -def ll_find(head, name): - """Ищет телефон по имени. Возвращает phone или None.""" - current = head - while current is not None: - if current['name'] == name: - return current['phone'] - current = current['next'] - return None - -def ll_delete(head, name): - """Удаляет узел с заданным именем. Возвращает новую голову.""" - if head is None: - return None - - # Если удаляем голову - if head['name'] == name: - return head['next'] - - # Ищем предыдущий узел - current = head - while current['next'] is not None: - if current['next']['name'] == name: - current['next'] = current['next']['next'] - return head - current = current['next'] - return head - -def ll_list_all(head): - """ - Возвращает список всех записей в виде [(name, phone), ...], - отсортированный по имени. Сама структура не сортируется. - """ - records = [] - current = head - while current is not None: - records.append((current['name'], current['phone'])) - current = current['next'] - records.sort(key=lambda x: x[0]) # сортировка по имени - return record \ No newline at end of file diff --git a/src/measure_time.py b/src/measure_time.py deleted file mode 100644 index f84fe2a..0000000 --- a/src/measure_time.py +++ /dev/null @@ -1,129 +0,0 @@ -""" -Экспериментальная часть. Пункт 2: Инструменты замера времени. -Цель: предоставить функции для многократного измерения времени выполнения -операций со структурами данных (LinkedList, HashTable, BST). - -Особенности: -- Используется time.perf_counter() для высокой точности. -- Каждый эксперимент повторяется min_runs раз (по умолчанию 5), результаты сохраняются. -- Вычисляется среднее арифметическое и список всех замеров. -- Результаты можно напрямую сохранить в CSV. -""" - -import time -from typing import List, Tuple, Callable, Any -import random - -# Предполагается, что generate_test_data из пункта 1 уже определена -# from experimental_part1 import generate_test_data # если код в другом файле - -# ========== 1. Базовые замеры ========== - -def measure_time(func: Callable, *args, **kwargs) -> float: - """ - Измеряет время выполнения функции func(*args, **kwargs). - Возвращает время в секундах (float). - """ - start = time.perf_counter() - result = func(*args, **kwargs) - end = time.perf_counter() - return end - start, result - -# ========== 2. Многократные замеры с усреднением ========== - -def run_experiment(func: Callable, args: Tuple, min_runs: int = 5) -> Tuple[float, List[float]]: - """ - Повторяет замер функции func(*args) минимум min_runs раз. - Возвращает (среднее_время, список_всех_замеров). - """ - times = [] - for _ in range(min_runs): - elapsed, _ = measure_time(func, *args) - times.append(elapsed) - avg_time = sum(times) / len(times) - return avg_time, times - -# ========== 3. Тестовые сценарии (заглушки для демонстрации) ========== - -# Ниже приведены примеры-заглушки для структур данных. -# В реальной работе их нужно заменить на реализованные функции. - -def stub_insert(structure, name, phone): - """Заглушка для вставки.""" - pass - -def stub_find(structure, name): - """Заглушка для поиска.""" - return None - -def stub_delete(structure, name): - """Заглушка для удаления.""" - pass - -def stub_list_all(structure): - """Заглушка для получения всех записей.""" - return [] - -# Пример функции, которая вставляет все записи из списка в структуру -def insert_all(structure, records, insert_func): - """ - Выполняет вставку всех записей (name, phone) в structure, - используя функцию insert_func(structure, name, phone). - """ - for name, phone in records: - insert_func(structure, name, phone) - -# Пример замера вставки для конкретной структуры -def benchmark_insert(structure_creator, records, insert_func, runs=5): - """ - Создаёт новую структуру через structure_creator(), - затем измеряет время вставки всех записей. - """ - def _insert_all(): - structure = structure_creator() - insert_all(structure, records, insert_func) - return structure - - avg_time, all_times = run_experiment(_insert_all, args=(), min_runs=runs) - return avg_time, all_times - -# ========== 4. Пример использования (демонстрация) ========== - -if __name__ == "__main__": - # Фиксируем seed для воспроизводимости - random.seed(42) - - # Генерируем тестовые данные (пункт 1) - N = 10000 - records_shuffled, records_sorted = generate_test_data(N, duplicate_names_ratio=0.1) - - # Выбираем 100 случайных имён для поиска (существующих) и 10 несуществующих - existing_names = [name for name, _ in records_shuffled[:100]] # первые 100 имён - nonexisting_names = [f"None_{i}" for i in range(10)] - - # Для демонстрации используем заглушки - def dummy_creator(): - return "dummy_structure" - - print("=== Демонстрация замера времени (заглушки) ===") - avg, times = benchmark_insert(dummy_creator, records_shuffled, stub_insert, runs=3) - print(f"Среднее время вставки (заглушка): {avg:.6f} сек") - print(f"Все замеры: {times}") - - # Пример сбора результатов для CSV - results = [ - ["Структура", "Режим", "Операция", "Время (сек)"], - ["LinkedList", "случайный", "вставка", 0.123], - # ... реальные данные появятся после реализации структур - ] - - # Сохранение в CS - - -V (раскомментировать при необходимости) - # import csv - # with open("docs/data/results.csv", "w", newline="") as f: - # writer = csv.writer(f) - # writer.writerows(results) - - print("\nГотово. Замеры можно проводить после реализации структур.") \ No newline at end of file