2026-rff_mp/ivankinad/task1/laba1.py
2026-09-05 01:36:33 +03:00

292 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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'")