import time import random import csv import os from phone_book import ( ll_insert, ll_find, ll_delete, ll_list_all, ht_make, ht_insert, ht_find, ht_delete, ht_list_all, bst_insert, bst_find, bst_delete, bst_list_all, ) N = 10_000 REPEATS = 5 SEARCH_COUNT = 110 DELETE_COUNT = 50 HT_SIZE = 256 RANDOM_SEED = 42 random.seed(RANDOM_SEED) OUTPUT_DIR = os.path.dirname(__file__) os.makedirs(OUTPUT_DIR, exist_ok=True) CSV_PATH = os.path.join(OUTPUT_DIR, 'results.csv') def generate_records(n): records = [(f"User_{i:05d}", f"+7{random.randint(1000000000, 9999999999)}") for i in range(n)] return records records_base = generate_records(N) records_shuffled = records_base[:] random.shuffle(records_shuffled) records_sorted = sorted(records_base, key=lambda x: x[0]) existing_names = [r[0] for r in random.sample(records_base, 100)] missing_names = [f"None_{i}" for i in range(10)] search_names = existing_names + missing_names delete_names = [r[0] for r in random.sample(records_base, DELETE_COUNT)] def measure(func, *args, **kwargs): start = time.perf_counter() result = func(*args, **kwargs) end = time.perf_counter() return end - start, result def bench_linked_list(records, mode_label): times = {'insert': [], 'find': [], 'delete': []} for _ in range(REPEATS): head = None t_start = time.perf_counter() for name, phone in records: head = ll_insert(head, name, phone) times['insert'].append(time.perf_counter() - t_start) t_start = time.perf_counter() for name in search_names: ll_find(head, name) times['find'].append(time.perf_counter() - t_start) t_start = time.perf_counter() for name in delete_names: head = ll_delete(head, name) times['delete'].append(time.perf_counter() - t_start) return times def bench_hash_table(records, mode_label): times = {'insert': [], 'find': [], 'delete': []} for _ in range(REPEATS): buckets = ht_make(HT_SIZE) t_start = time.perf_counter() for name, phone in records: ht_insert(buckets, name, phone) times['insert'].append(time.perf_counter() - t_start) t_start = time.perf_counter() for name in search_names: ht_find(buckets, name) times['find'].append(time.perf_counter() - t_start) t_start = time.perf_counter() for name in delete_names: ht_delete(buckets, name) times['delete'].append(time.perf_counter() - t_start) return times def bench_bst(records, mode_label): times = {'insert': [], 'find': [], 'delete': []} for _ in range(REPEATS): root = None t_start = time.perf_counter() for name, phone in records: root = bst_insert(root, name, phone) times['insert'].append(time.perf_counter() - t_start) t_start = time.perf_counter() for name in search_names: bst_find(root, name) times['find'].append(time.perf_counter() - t_start) t_start = time.perf_counter() for name in delete_names: root = bst_delete(root, name) times['delete'].append(time.perf_counter() - t_start) return times def avg(lst): return sum(lst) / len(lst) def run_all(): print(f"Запуск бенчмарков: N={N}, повторений={REPEATS}\n") print(f"{'Структура':<15} {'Режим':<12} {'Операция':<10} " f"{'Среднее (с)':<14} {'Все замеры'}") print("-" * 80) all_results = [["Структура", "Режим", "Операция", "Среднее (с)"] + [f"Замер_{i+1}" for i in range(REPEATS)]] datasets = [ (records_shuffled, "случайный"), (records_sorted, "сортированный"), ] benchmarks = [ ("LinkedList", bench_linked_list), ("HashTable", bench_hash_table), ("BST", bench_bst), ] for ds_records, ds_mode in datasets: for struct_name, bench_func in benchmarks: print(f"\n [{struct_name}] режим: {ds_mode}") if struct_name == "BST" and ds_mode == "сортированный": import sys sys.setrecursionlimit(50_000) times = bench_func(ds_records, ds_mode) for op, op_times in times.items(): mean = avg(op_times) row = [struct_name, ds_mode, op, f"{mean:.6f}"] + \ [f"{t:.6f}" for t in op_times] all_results.append(row) print(f" {op:<10} среднее={mean:.6f}с " f"замеры={[f'{t:.4f}' for t in op_times]}") with open(CSV_PATH, 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerows(all_results) print(f"\n✅ Результаты сохранены в: {CSV_PATH}") return all_results def smoke_test(): print("=== Smoke Test ===\n") test_data = [("Alice", "111"), ("Bob", "222"), ("Charlie", "333")] head = None for name, phone in test_data: head = ll_insert(head, name, phone) assert ll_find(head, "Alice") == "111" assert ll_find(head, "Bob") == "222" assert ll_find(head, "Nobody") is None head = ll_delete(head, "Bob") assert ll_find(head, "Bob") is None sorted_ll = ll_list_all(head) assert sorted_ll == [("Alice", "111"), ("Charlie", "333")] print("✅ LinkedList — OK") buckets = ht_make(16) for name, phone in test_data: ht_insert(buckets, name, phone) assert ht_find(buckets, "Charlie") == "333" assert ht_find(buckets, "Nobody") is None ht_delete(buckets, "Alice") assert ht_find(buckets, "Alice") is None sorted_ht = ht_list_all(buckets) assert sorted_ht == [("Bob", "222"), ("Charlie", "333")] print("✅ HashTable — OK") root = None for name, phone in test_data: root = bst_insert(root, name, phone) assert bst_find(root, "Alice") == "111" assert bst_find(root, "Nobody") is None root = bst_delete(root, "Alice") assert bst_find(root, "Alice") is None sorted_bst = bst_list_all(root) assert sorted_bst == [("Bob", "222"), ("Charlie", "333")] print("✅ BST — OK") print("\nВсе тесты пройдены!\n") if __name__ == "__main__": smoke_test() results = run_all()