import csv import random import sys import time import threading import matplotlib.pyplot as plt sys.setrecursionlimit(30000) threading.stack_size(64*1024*1024) def ll_insert(head, name, phone): current = head while current is not None: if current["name"] == name: current["phone"] = phone return head current = current["next"] fresh_node = {"name": name, "phone": phone, "next": head} return fresh_node def ll_find(head, name): current = head while current is not None: if current["name"] == name: return current["phone"] current = current["next"] return None def ll_delete(head, name): current = head previous = None while current is not None: if current["name"] == name: if previous is None: return current["next"] else: previous["next"] = current["next"] return head previous = current current = current["next"] return head def ll_list_all(head): entries = [] current = head while current is not None: entries.append((current["name"], current["phone"])) current = current["next"] entries.sort(key=lambda item: item[0]) return entries def ht_create(size=1000): return [None] * size def ht_insert(buckets, name, phone): bucket_idx = abs(hash(name)) % len(buckets) buckets[bucket_idx] = ll_insert(buckets[bucket_idx], name, phone) def ht_find(buckets, name): bucket_idx = abs(hash(name)) % len(buckets) return ll_find(buckets[bucket_idx], name) def ht_delete(buckets, name): bucket_idx = abs(hash(name)) % len(buckets) buckets[bucket_idx] = ll_delete(buckets[bucket_idx], name) def ht_list_all(buckets): entries = [] for head_node in buckets: current = head_node while current is not None: entries.append((current["name"], current["phone"])) current = current["next"] entries.sort(key=lambda item: item[0]) return entries def bst_insert(root, name, phone): if root is None: return {"name": name, "phone": phone, "left": None, "right": None} if name == root["name"]: root["phone"] = phone elif name < root["name"]: root["left"] = bst_insert(root["left"], name, phone) else: root["right"] = bst_insert(root["right"], name, phone) return root def bst_find(root, name): 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 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"] if root["right"] is None: return root["left"] successor = root["right"] while successor["left"] is not None: successor = successor["left"] root["name"] = successor["name"] root["phone"] = successor["phone"] root["right"] = bst_delete(root["right"], successor["name"]) return root def bst_list_all(root): entries = [] def _inorder(node): if node is not None: _inorder(node["left"]) entries.append((node["name"], node["phone"])) _inorder(node["right"]) _inorder(root) return entries def perform_benchmark(): total_records = 10000 random.seed(42) ordered_records = [(f"User_{i:05d}", f"8-999-123-{i:04d}") for i in range(total_records)] shuffled_records = ordered_records.copy() random.shuffle(shuffled_records) existing_searches = [random.choice(ordered_records)[0] for _ in range(100)] non_existing_searches = [f"None_{i}" for i in range(10)] search_queries = existing_searches + non_existing_searches deletion_targets = [random.choice(ordered_records)[0] for _ in range(50)] output_rows = [["Structure", "Mode", "Operation", "Time (sec)"]] graph_entries = [] def execute_trial(structure_kind, data_mode, data_collection): print(f"Starting: {structure_kind} | Mode: {data_mode}...") insertion_measurements, search_measurements, deletion_measurements = [], [], [] for trial_num in range(1, 6): if structure_kind == "LinkedList": container = None elif structure_kind == "HashTable": container = ht_create(size=1000) elif structure_kind == "BST": container = None #Вставка timer_start = time.perf_counter() if structure_kind == "LinkedList": for name, phone in data_collection: container = ll_insert(container, name, phone) elif structure_kind == "HashTable": for name, phone in data_collection: ht_insert(container, name, phone) elif structure_kind == "BST": for name, phone in data_collection: container = bst_insert(container, name, phone) insert_elapsed = time.perf_counter() - timer_start insertion_measurements.append(insert_elapsed) output_rows.append([structure_kind, data_mode, f"insert (trial {trial_num})", f"{insert_elapsed:.6f}"]) #Поиск timer_start = time.perf_counter() if structure_kind == "LinkedList": for name in search_queries: ll_find(container, name) elif structure_kind == "HashTable": for name in search_queries: ht_find(container, name) elif structure_kind == "BST": for name in search_queries: bst_find(container, name) search_elapsed = time.perf_counter() - timer_start search_measurements.append(search_elapsed) output_rows.append([structure_kind, data_mode, f"find (trial {trial_num})", f"{search_elapsed:.6f}"]) #Удаление timer_start = time.perf_counter() if structure_kind == "LinkedList": for name in deletion_targets: container = ll_delete(container, name) elif structure_kind == "HashTable": for name in deletion_targets: ht_delete(container, name) elif structure_kind == "BST": for name in deletion_targets: container = bst_delete(container, name) delete_elapsed = time.perf_counter() - timer_start deletion_measurements.append(delete_elapsed) output_rows.append([structure_kind, data_mode, f"delete (trial {trial_num})", f"{delete_elapsed:.6f}"]) # Запись средних значений output_rows.append([structure_kind, data_mode, "Insert (avg)", f"{sum(insertion_measurements)/5:.6f}"]) output_rows.append([structure_kind, data_mode, "Find (avg)", f"{sum(search_measurements)/5:.6f}"]) output_rows.append([structure_kind, data_mode, "Delete (avg)", f"{sum(deletion_measurements)/5:.6f}"]) avg_insertion = sum(insertion_measurements) / 5 avg_search = sum(search_measurements) / 5 avg_deletion = sum(deletion_measurements) / 5 graph_entries.append((structure_kind, data_mode, avg_insertion, avg_search, avg_deletion)) # Запуск всех тестов execute_trial("LinkedList", "random", shuffled_records) execute_trial("LinkedList", "sorted", ordered_records) execute_trial("HashTable", "random", shuffled_records) execute_trial("HashTable", "sorted", ordered_records) execute_trial("BST", "random", shuffled_records) execute_trial("BST", "sorted", ordered_records) with open("benchmark_output.csv", "w", newline="", encoding="utf-8") as csv_file: csv_writer = csv.writer(csv_file) csv_writer.writerows(output_rows) print("\n[Success] All benchmarks completed! Results saved to 'benchmark_output.csv'.") generate_performance_charts(graph_entries) def generate_performance_charts(plot_data): if not plot_data: print("Нет данных для построения графиков") return # Подготовка данных structures = ['LinkedList', 'HashTable', 'BST'] modes = ['random', 'sorted'] operations = ['Insert', 'Find', 'Delete'] # Создаем фигуру с тремя подграфиками fig, axes = plt.subplots(1, 3, figsize=(15, 5)) for idx, operation in enumerate(operations): ax = axes[idx] # Данные для текущей операции x_positions = [] y_values = [] labels = [] for structure in structures: for mode in modes: # Находим данные для этой комбинации for data in plot_data: if data[0] == structure and data[1] == mode: value = data[2 + idx] # 2=insert, 3=find, 4=delete x_positions.append(len(x_positions)) y_values.append(value) labels.append(f"{structure}\n{mode}") # Создаем столбчатую диаграмму bars = ax.bar(x_positions, y_values, color=['skyblue', 'lightcoral']*3) # Настройка графика ax.set_title(f'Операция: {operation}', fontsize=14, fontweight='bold') ax.set_ylabel('Время (сек)', fontsize=12) ax.set_xticks(x_positions) ax.set_xticklabels(labels, rotation=45, ha='right', fontsize=10) ax.grid(axis='y', alpha=0.3) # Добавляем значения над столбцами for bar, value in zip(bars, y_values): ax.text(bar.get_x() + bar.get_width()/2, bar.get_height(), f'{value:.4f}', ha='center', va='bottom', fontsize=8) plt.tight_layout() plt.savefig('performance_charts.png', dpi=300, bbox_inches='tight') plt.show() print("Графики сохранены в 'performance_charts.png'") if __name__ == '__main__': benchmark_thread = threading.Thread(target=perform_benchmark) benchmark_thread.start() benchmark_thread.join() print("\nПрограмма завершена. Проверьте файл 'performance_charts.png'")