experiment_code = '' import time import csv import random import sys import matplotlib.pyplot as plt import numpy as np from linked_list import ll_insert, ll_find, ll_delete, ll_list_all from hash_table import ht_insert, ht_find, ht_delete, ht_list_all from bst import bst_insert, bst_find, bst_delete, bst_list_all sys.setrecursionlimit(20000) # параметры N = 5000 # Количество записей NUM_RUNS = 5 # Количество прогонов для усреднения BUCKET_SIZE = N // 2 # Размер хеш-таблицы (load factor ~2) def generate_data(n): records = [] for i in range(n): name = f"User_{i:05d}" phone = f"+7{random.randint(9000000000, 9999999999)}" records.append((name, phone)) records_shuffled = records.copy() random.shuffle(records_shuffled) records_sorted = sorted(records, key=lambda x: x[0]) return records, records_shuffled, records_sorted def run_linked_list_experiment(records, search_existing, search_nonexistent, names_to_delete): head = None # Вставка start = time.perf_counter() for name, phone in records: head = ll_insert(head, name, phone) end = time.perf_counter() insert_time = end - start # Поиск start = time.perf_counter() for name in search_existing: ll_find(head, name) for name in search_nonexistent: ll_find(head, name) end = time.perf_counter() find_time = end - start # Удаление start = time.perf_counter() for name in names_to_delete: head = ll_delete(head, name) end = time.perf_counter() delete_time = end - start return insert_time, find_time, delete_time def run_hash_table_experiment(records, search_existing, search_nonexistent, names_to_delete): buckets = [None] * BUCKET_SIZE # Вставка start = time.perf_counter() for name, phone in records: ht_insert(buckets, name, phone) end = time.perf_counter() insert_time = end - start # Поиск start = time.perf_counter() for name in search_existing: ht_find(buckets, name) for name in search_nonexistent: ht_find(buckets, name) end = time.perf_counter() find_time = end - start # Удаление start = time.perf_counter() for name in names_to_delete: ht_delete(buckets, name) end = time.perf_counter() delete_time = end - start return insert_time, find_time, delete_time def run_bst_experiment(records, search_existing, search_nonexistent, names_to_delete): root = None # Вставка start = time.perf_counter() for name, phone in records: root = bst_insert(root, name, phone) end = time.perf_counter() insert_time = end - start # Поиск start = time.perf_counter() for name in search_existing: bst_find(root, name) for name in search_nonexistent: bst_find(root, name) end = time.perf_counter() find_time = end - start # Удаление start = time.perf_counter() for name in names_to_delete: root = bst_delete(root, name) end = time.perf_counter() delete_time = end - start return insert_time, find_time, delete_time def run_all_experiments(): print("=" * 60) print("ЭКСПЕРИМЕНТ: Сравнение структур данных") print(f"N = {N}, прогонов = {NUM_RUNS}") print("=" * 60) # Генерация данных print("\\n[1/5] Генерация тестовых данных...") records, records_shuffled, records_sorted = generate_data(N) # Подготовка данных для поиска и удаления (фиксируем seed для воспроизводимости) random.seed(42) existing_names = [r[0] for r in records] search_existing = random.sample(existing_names, 100) search_nonexistent = [f"None_{i:05d}" for i in range(10)] names_to_delete = random.sample(existing_names, 50) print(f" Записей: {len(records)}") print(f" Поиск: {len(search_existing)} существующих + {len(search_nonexistent)} несуществующих") print(f" Удаление: {len(names_to_delete)} записей") # Хранение результатов all_results = [] print("\\n[2/5] Linked List...") for run in range(NUM_RUNS): t_insert, t_find, t_delete = run_linked_list_experiment( records_shuffled, search_existing, search_nonexistent, names_to_delete ) all_results.append({ 'Структура': 'LinkedList', 'Режим': 'случайный', 'Прогон': run + 1, 'Вставка': t_insert, 'Поиск': t_find, 'Удаление': t_delete }) print(f" Случайный прогон {run + 1}: insert={t_insert:.4f}s, find={t_find:.4f}s, delete={t_delete:.4f}s") for run in range(NUM_RUNS): t_insert, t_find, t_delete = run_linked_list_experiment( records_sorted, search_existing, search_nonexistent, names_to_delete ) all_results.append({ 'Структура': 'LinkedList', 'Режим': 'отсортированный', 'Прогон': run + 1, 'Вставка': t_insert, 'Поиск': t_find, 'Удаление': t_delete }) print(f" Отсортированный прогон {run + 1}: insert={t_insert:.4f}s, find={t_find:.4f}s, delete={t_delete:.4f}s") print("\\n[3/5] Hash Table...") for run in range(NUM_RUNS): t_insert, t_find, t_delete = run_hash_table_experiment( records_shuffled, search_existing, search_nonexistent, names_to_delete ) all_results.append({ 'Структура': 'HashTable', 'Режим': 'случайный', 'Прогон': run + 1, 'Вставка': t_insert, 'Поиск': t_find, 'Удаление': t_delete }) print(f" Случайный прогон {run + 1}: insert={t_insert:.4f}s, find={t_find:.4f}s, delete={t_delete:.4f}s") for run in range(NUM_RUNS): t_insert, t_find, t_delete = run_hash_table_experiment( records_sorted, search_existing, search_nonexistent, names_to_delete ) all_results.append({ 'Структура': 'HashTable', 'Режим': 'отсортированный', 'Прогон': run + 1, 'Вставка': t_insert, 'Поиск': t_find, 'Удаление': t_delete }) print(f" Отсортированный прогон {run + 1}: insert={t_insert:.4f}s, find={t_find:.4f}s, delete={t_delete:.4f}s") print("\\n[4/5] BST...") for run in range(NUM_RUNS): t_insert, t_find, t_delete = run_bst_experiment( records_shuffled, search_existing, search_nonexistent, names_to_delete ) all_results.append({ 'Структура': 'BST', 'Режим': 'случайный', 'Прогон': run + 1, 'Вставка': t_insert, 'Поиск': t_find, 'Удаление': t_delete }) print(f" Случайный прогон {run + 1}: insert={t_insert:.4f}s, find={t_find:.4f}s, delete={t_delete:.4f}s") for run in range(NUM_RUNS): t_insert, t_find, t_delete = run_bst_experiment( records_sorted, search_existing, search_nonexistent, names_to_delete ) all_results.append({ 'Структура': 'BST', 'Режим': 'отсортированный', 'Прогон': run + 1, 'Вставка': t_insert, 'Поиск': t_find, 'Удаление': t_delete }) print(f" Отсортированный прогон {run + 1}: insert={t_insert:.4f}s, find={t_find:.4f}s, delete={t_delete:.4f}s") print("\\n[5/5] Сохранение результатов...") # Сырые данные with open('../docs/data/results_raw.csv', 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerow(['Структура', 'Режим', 'Прогон', 'Вставка (сек)', 'Поиск (сек)', 'Удаление (сек)']) for r in all_results: writer.writerow([r['Структура'], r['Режим'], r['Прогон'], r['Вставка'], r['Поиск'], r['Удаление']]) print(" Сохранено: ../docs/data/results_raw.csv") # Сводная таблица from collections import defaultdict avg_results = defaultdict(lambda: {'insert': [], 'find': [], 'delete': []}) for r in all_results: key = (r['Структура'], r['Режим']) avg_results[key]['insert'].append(r['Вставка']) avg_results[key]['find'].append(r['Поиск']) avg_results[key]['delete'].append(r['Удаление']) with open('../docs/data/results_summary.csv', 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerow(['Структура', 'Режим', 'Операция', 'Среднее (сек)', 'Мин (сек)', 'Макс (сек)']) for (struct, mode), times in avg_results.items(): writer.writerow([struct, mode, 'Вставка', f"{sum(times['insert']) / len(times['insert']):.6f}", f"{min(times['insert']):.6f}", f"{max(times['insert']):.6f}"]) writer.writerow([struct, mode, 'Поиск', f"{sum(times['find']) / len(times['find']):.6f}", f"{min(times['find']):.6f}", f"{max(times['find']):.6f}"]) writer.writerow([struct, mode, 'Удаление', f"{sum(times['delete']) / len(times['delete']):.6f}", f"{min(times['delete']):.6f}", f"{max(times['delete']):.6f}"]) print(" Сохранено: ../docs/data/results_summary.csv") print(" Построение графиков...") build_charts(avg_results) print(" Сохранено: ../docs/data/charts.png") print("\\n" + "=" * 60) print("ЭКСПЕРИМЕНТ ЗАВЕРШЁН!") print("=" * 60) return all_results, avg_results def build_charts(avg_results): """Строит графики сравнения производительности.""" fig, axes = plt.subplots(2, 3, figsize=(18, 12)) fig.suptitle(f'Сравнение производительности структур данных (N={N})', fontsize=16, fontweight='bold') structures = ['LinkedList', 'HashTable', 'BST'] modes = ['случайный', 'отсортированный'] struct_colors = {'LinkedList': '#FF6B6B', 'HashTable': '#4ECDC4', 'BST': '#45B7D1'} # Подготовка данных для графиков def get_value(struct, mode, op): key = (struct, mode) if key in avg_results: return sum(avg_results[key][op]) / len(avg_results[key][op]) return 0 # График 1: Вставка ax = axes[0, 0] x = np.arange(len(modes)) width = 0.25 for i, struct in enumerate(structures): vals = [get_value(struct, mode, 'insert') for mode in modes] ax.bar(x + i * width, vals, width, label=struct, color=struct_colors[struct]) ax.set_xlabel('Режим данных') ax.set_ylabel('Время (сек)') ax.set_title('Вставка') ax.set_xticks(x + width) ax.set_xticklabels(modes) ax.legend() ax.set_yscale('log') ax.grid(True, alpha=0.3) # График 2: Поиск ax = axes[0, 1] for i, struct in enumerate(structures): vals = [get_value(struct, mode, 'find') for mode in modes] ax.bar(x + i * width, vals, width, label=struct, color=struct_colors[struct]) ax.set_xlabel('Режим данных') ax.set_ylabel('Время (сек)') ax.set_title('Поиск (110 операций)') ax.set_xticks(x + width) ax.set_xticklabels(modes) ax.legend() ax.set_yscale('log') ax.grid(True, alpha=0.3) # График 3: Удаление ax = axes[0, 2] for i, struct in enumerate(structures): vals = [get_value(struct, mode, 'delete') for mode in modes] ax.bar(x + i * width, vals, width, label=struct, color=struct_colors[struct]) ax.set_xlabel('Режим данных') ax.set_ylabel('Время (сек)') ax.set_title('Удаление (50 операций)') ax.set_xticks(x + width) ax.set_xticklabels(modes) ax.legend() ax.set_yscale('log') ax.grid(True, alpha=0.3) # График 4: BST деградация ax = axes[1, 0] bst_random = get_value('BST', 'случайный', 'insert') bst_sorted = get_value('BST', 'отсортированный', 'insert') ax.bar(['Случайный', 'Отсортированный'], [bst_random, bst_sorted], color=['#45B7D1', '#E74C3C']) ax.set_ylabel('Время (сек)') ax.set_title('BST: влияние порядка данных на вставку') for i, v in enumerate([bst_random, bst_sorted]): ax.text(i, v + max(v * 0.05, 0.01), f'{v:.3f}s', ha='center', fontweight='bold') ax.grid(True, alpha=0.3) # График 5: Случайный режим — все операции ax = axes[1, 1] x = np.arange(len(structures)) width = 0.25 insert_vals = [get_value(s, 'случайный', 'insert') for s in structures] find_vals = [get_value(s, 'случайный', 'find') for s in structures] delete_vals = [get_value(s, 'случайный', 'delete') for s in structures] ax.bar(x - width, insert_vals, width, label='Вставка', color='#FF6B6B') ax.bar(x, find_vals, width, label='Поиск', color='#4ECDC4') ax.bar(x + width, delete_vals, width, label='Удаление', color='#45B7D1') ax.set_xlabel('Структура данных') ax.set_ylabel('Время (сек)') ax.set_title('Случайный режим: все операции') ax.set_xticks(x) ax.set_xticklabels(structures) ax.legend() ax.set_yscale('log') ax.grid(True, alpha=0.3) # График 6: Отсортированный режим — поиск и удаление ax = axes[1, 2] find_vals = [get_value(s, 'отсортированный', 'find') for s in structures] delete_vals = [get_value(s, 'отсортированный', 'delete') for s in structures] ax.bar(x - width / 2, find_vals, width, label='Поиск', color='#4ECDC4') ax.bar(x + width / 2, delete_vals, width, label='Удаление', color='#45B7D1') ax.set_xlabel('Структура данных') ax.set_ylabel('Время (сек)') ax.set_title('Отсортированный режим: поиск и удаление') ax.set_xticks(x) ax.set_xticklabels(structures) ax.legend() ax.set_yscale('log') ax.grid(True, alpha=0.3) plt.tight_layout() plt.savefig('../docs/data/charts.png', dpi=150, bbox_inches='tight') plt.close() if __name__ == '__main__': run_all_experiments() with open('/mnt/agents/output/lab1/src/experiment.py', 'w', encoding='utf-8') as f: f.write(experiment_code) print("✅ experiment.py создан")