diff --git a/shalovsa/lab1/docs/data/laba.py b/shalovsa/lab1/docs/data/laba.py new file mode 100644 index 0000000..547fd54 --- /dev/null +++ b/shalovsa/lab1/docs/data/laba.py @@ -0,0 +1,210 @@ +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()