From 74c13ec0fb238646cfe47679837c1795e9f09522 Mon Sep 17 00:00:00 2001 From: semyanovra Date: Sun, 24 May 2026 21:16:18 +0000 Subject: [PATCH] [1] add performance experiments and plotting --- semyanovra/docs/data/1-st/main.py | 196 +++++++++++++++++++++++++----- 1 file changed, 165 insertions(+), 31 deletions(-) diff --git a/semyanovra/docs/data/1-st/main.py b/semyanovra/docs/data/1-st/main.py index 072a213..3d416a2 100644 --- a/semyanovra/docs/data/1-st/main.py +++ b/semyanovra/docs/data/1-st/main.py @@ -1,3 +1,12 @@ +import random +import time +import csv +import sys +import pandas as pd +import matplotlib.pyplot as plt + +sys.setrecursionlimit(20000) + def ll_insert(head, name, phone): current = head while current is not None: @@ -86,7 +95,6 @@ def bst_create_node(name, phone): def bst_insert(root, name, phone): if root is None: return bst_create_node(name, phone) - if name == root['name']: root['phone'] = phone elif name < root['name']: @@ -113,7 +121,6 @@ def bst_find_min(node): 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']: @@ -123,7 +130,6 @@ def bst_delete(root, name): return root['right'] if root['right'] is None: return root['left'] - min_node = bst_find_min(root['right']) root['name'] = min_node['name'] root['phone'] = min_node['phone'] @@ -132,38 +138,166 @@ def bst_delete(root, name): def bst_list_all(root): result = [] - - def inorder_traverse(node): + def inorder(node): if node is None: return - inorder_traverse(node['left']) + inorder(node['left']) result.append((node['name'], node['phone'])) - inorder_traverse(node['right']) - - inorder_traverse(root) + inorder(node['right']) + inorder(root) return result +def generate_records(num_records, seed=42): + random.seed(seed) + records = [] + for i in range(1, num_records + 1): + name = f"User_{i:05d}" + phone = f"{random.randint(100,999)}-{random.randint(1000,9999)}" + records.append((name, phone)) + return records + +def prepare_datasets(base_records): + shuffled = base_records.copy() + random.shuffle(shuffled) + sorted_records = sorted(base_records, key=lambda x: x[0]) + return shuffled, sorted_records + + +def run_experiment_for_structure(struct_funcs, records, mode_name, repeats=5): + results = [] + for rep in range(repeats): + ds = struct_funcs['create']() + + start = time.perf_counter() + for name, phone in records: + ds = struct_funcs['insert'](ds, name, phone) + insert_time = time.perf_counter() - start + + existing_names = [rec[0] for rec in records] + sample_existing = random.sample(existing_names, 100) + nonexistent = [f"None_{i}" for i in range(10)] + search_names = sample_existing + nonexistent + random.shuffle(search_names) + + start = time.perf_counter() + for name in search_names: + _ = struct_funcs['find'](ds, name) + find_time = time.perf_counter() - start + + to_delete = random.sample(existing_names, 50) + start = time.perf_counter() + for name in to_delete: + ds = struct_funcs['delete'](ds, name) + delete_time = time.perf_counter() - start + + results.append({ + 'structure': struct_funcs['name'], + 'mode': mode_name, + 'repetition': rep + 1, + 'insert_time': insert_time, + 'find_time': find_time, + 'delete_time': delete_time + }) + return results + + +def main_experiment(): + N = 10000 + REPEATS = 5 + + print("Генерация тестовых данных...") + base_records = generate_records(N) + shuffled_records, sorted_records = prepare_datasets(base_records) + print(f"Создано {N} записей. Случайный порядок и отсортированный готовы.") + + structures = { + 'LinkedList': { + 'name': 'LinkedList', + 'create': lambda: None, + 'insert': ll_insert, + 'find': ll_find, + 'delete': ll_delete + }, + 'HashTable': { + 'name': 'HashTable', + 'create': ht_create, + 'insert': ht_insert, + 'find': ht_find, + 'delete': ht_delete + }, + 'BST': { + 'name': 'BST', + 'create': lambda: None, + 'insert': bst_insert, + 'find': bst_find, + 'delete': bst_delete + } + } + + all_results = [] + + for struct_name, funcs in structures.items(): + print(f"Тестирование {struct_name} на случайном порядке...") + all_results.extend(run_experiment_for_structure(funcs, shuffled_records, 'random', REPEATS)) + + print(f"Тестирование {struct_name} на отсортированном порядке...") + all_results.extend(run_experiment_for_structure(funcs, sorted_records, 'sorted', REPEATS)) + + csv_file = "experiment_results.csv" + with open(csv_file, 'w', newline='', encoding='utf-8') as f: + writer = csv.writer(f) + writer.writerow(['Structure', 'Mode', 'Repeat', 'Insert (sec)', 'Search (sec)', 'Delete (sec)']) + for rec in all_results: + writer.writerow([ + rec['structure'], + rec['mode'], + rec['repetition'], + f"{rec['insert_time']:.6f}", + f"{rec['find_time']:.6f}", + f"{rec['delete_time']:.6f}" + ]) + print(f"Результаты сохранены в {csv_file}") + + plot_results(csv_file) + + +def plot_results(csv_path): + df = pd.read_csv(csv_path) + mean_times = df.groupby(['Structure', 'Mode'])[['Insert (sec)', 'Search (sec)', 'Delete (sec)']].mean().reset_index() + + structures = mean_times['Structure'].unique() + modes = mean_times['Mode'].unique() + + fig, axes = plt.subplots(1, 3, figsize=(15, 5)) + operations = ['Insert (sec)', 'Search (sec)', 'Delete (sec)'] + titles = ['Вставка', 'Поиск', 'Удаление'] + + for ax, op, title in zip(axes, operations, titles): + x = range(len(structures)) + width = 0.35 + + random_vals = [] + sorted_vals = [] + for s in structures: + rand_row = mean_times[(mean_times['Structure'] == s) & (mean_times['Mode'] == 'random')] + sort_row = mean_times[(mean_times['Structure'] == s) & (mean_times['Mode'] == 'sorted')] + random_vals.append(rand_row[op].values[0] if not rand_row.empty else 0) + sorted_vals.append(sort_row[op].values[0] if not sort_row.empty else 0) + + ax.bar([i - width/2 for i in x], random_vals, width, label='Случайный порядок') + ax.bar([i + width/2 for i in x], sorted_vals, width, label='Отсортированный порядок') + ax.set_xticks(x) + ax.set_xticklabels(structures) + ax.set_ylabel('Время (секунды)') + ax.set_title(title) + ax.legend() + + plt.tight_layout() + plt.savefig('performance_comparison.png', dpi=150) + plt.show() + print("График сохранён как performance_comparison.png") + + if __name__ == "__main__": - print("=== Тестирование связного списка ===") - head = None - head = ll_insert(head, "Ivan", "123-456") - head = ll_insert(head, "Boris", "789-012") - print("LinkedList:", ll_list_all(head)) - - print("\n=== Тестирование хеш-таблицы ===") - ht = ht_create() - ht = ht_insert(ht, "Ivan", "123-456") - ht = ht_insert(ht, "Boris", "789-012") - print("HashTable:", ht_list_all(ht)) - - print("\n=== Тестирование BST ===") - bst_root = None - bst_root = bst_insert(bst_root, "Ivan", "123-456") - bst_root = bst_insert(bst_root, "Boris", "789-012") - bst_root = bst_insert(bst_root, "Anna", "345-678") - bst_root = bst_insert(bst_root, "Ivan", "111-222") - print("BST entries:", bst_list_all(bst_root)) - print("Find Ivan:", bst_find(bst_root, "Ivan")) - bst_root = bst_delete(bst_root, "Boris") - print("After delete Boris:", bst_list_all(bst_root)) \ No newline at end of file + main_experiment() \ No newline at end of file