task1
This commit is contained in:
parent
040d3236d9
commit
e6b4e51999
109
ivankinad/task1/benchmark_output.csv
Normal file
109
ivankinad/task1/benchmark_output.csv
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
Structure,Mode,Operation,Time (sec)
|
||||||
|
LinkedList,random,insert (trial 1),3.415125
|
||||||
|
LinkedList,random,find (trial 1),0.035397
|
||||||
|
LinkedList,random,delete (trial 1),0.017692
|
||||||
|
LinkedList,random,insert (trial 2),3.534952
|
||||||
|
LinkedList,random,find (trial 2),0.038819
|
||||||
|
LinkedList,random,delete (trial 2),0.021675
|
||||||
|
LinkedList,random,insert (trial 3),3.493529
|
||||||
|
LinkedList,random,find (trial 3),0.036592
|
||||||
|
LinkedList,random,delete (trial 3),0.018221
|
||||||
|
LinkedList,random,insert (trial 4),3.340745
|
||||||
|
LinkedList,random,find (trial 4),0.036098
|
||||||
|
LinkedList,random,delete (trial 4),0.017576
|
||||||
|
LinkedList,random,insert (trial 5),3.369741
|
||||||
|
LinkedList,random,find (trial 5),0.035302
|
||||||
|
LinkedList,random,delete (trial 5),0.017674
|
||||||
|
LinkedList,random,Insert (avg),3.430818
|
||||||
|
LinkedList,random,Find (avg),0.036442
|
||||||
|
LinkedList,random,Delete (avg),0.018568
|
||||||
|
LinkedList,sorted,insert (trial 1),3.118200
|
||||||
|
LinkedList,sorted,find (trial 1),0.037116
|
||||||
|
LinkedList,sorted,delete (trial 1),0.019387
|
||||||
|
LinkedList,sorted,insert (trial 2),3.338498
|
||||||
|
LinkedList,sorted,find (trial 2),0.036500
|
||||||
|
LinkedList,sorted,delete (trial 2),0.019001
|
||||||
|
LinkedList,sorted,insert (trial 3),3.136906
|
||||||
|
LinkedList,sorted,find (trial 3),0.037498
|
||||||
|
LinkedList,sorted,delete (trial 3),0.019219
|
||||||
|
LinkedList,sorted,insert (trial 4),3.253578
|
||||||
|
LinkedList,sorted,find (trial 4),0.036434
|
||||||
|
LinkedList,sorted,delete (trial 4),0.019333
|
||||||
|
LinkedList,sorted,insert (trial 5),3.207896
|
||||||
|
LinkedList,sorted,find (trial 5),0.038585
|
||||||
|
LinkedList,sorted,delete (trial 5),0.020473
|
||||||
|
LinkedList,sorted,Insert (avg),3.211016
|
||||||
|
LinkedList,sorted,Find (avg),0.037227
|
||||||
|
LinkedList,sorted,Delete (avg),0.019482
|
||||||
|
HashTable,random,insert (trial 1),0.010124
|
||||||
|
HashTable,random,find (trial 1),0.000093
|
||||||
|
HashTable,random,delete (trial 1),0.000052
|
||||||
|
HashTable,random,insert (trial 2),0.010397
|
||||||
|
HashTable,random,find (trial 2),0.000086
|
||||||
|
HashTable,random,delete (trial 2),0.000048
|
||||||
|
HashTable,random,insert (trial 3),0.009352
|
||||||
|
HashTable,random,find (trial 3),0.000081
|
||||||
|
HashTable,random,delete (trial 3),0.000046
|
||||||
|
HashTable,random,insert (trial 4),0.009326
|
||||||
|
HashTable,random,find (trial 4),0.000080
|
||||||
|
HashTable,random,delete (trial 4),0.000046
|
||||||
|
HashTable,random,insert (trial 5),0.010205
|
||||||
|
HashTable,random,find (trial 5),0.000081
|
||||||
|
HashTable,random,delete (trial 5),0.000046
|
||||||
|
HashTable,random,Insert (avg),0.009881
|
||||||
|
HashTable,random,Find (avg),0.000084
|
||||||
|
HashTable,random,Delete (avg),0.000048
|
||||||
|
HashTable,sorted,insert (trial 1),0.008975
|
||||||
|
HashTable,sorted,find (trial 1),0.000087
|
||||||
|
HashTable,sorted,delete (trial 1),0.000050
|
||||||
|
HashTable,sorted,insert (trial 2),0.009137
|
||||||
|
HashTable,sorted,find (trial 2),0.000086
|
||||||
|
HashTable,sorted,delete (trial 2),0.000050
|
||||||
|
HashTable,sorted,insert (trial 3),0.009460
|
||||||
|
HashTable,sorted,find (trial 3),0.000086
|
||||||
|
HashTable,sorted,delete (trial 3),0.000049
|
||||||
|
HashTable,sorted,insert (trial 4),0.008977
|
||||||
|
HashTable,sorted,find (trial 4),0.000085
|
||||||
|
HashTable,sorted,delete (trial 4),0.000049
|
||||||
|
HashTable,sorted,insert (trial 5),0.009416
|
||||||
|
HashTable,sorted,find (trial 5),0.000094
|
||||||
|
HashTable,sorted,delete (trial 5),0.000053
|
||||||
|
HashTable,sorted,Insert (avg),0.009193
|
||||||
|
HashTable,sorted,Find (avg),0.000087
|
||||||
|
HashTable,sorted,Delete (avg),0.000050
|
||||||
|
BST,random,insert (trial 1),0.031499
|
||||||
|
BST,random,find (trial 1),0.000274
|
||||||
|
BST,random,delete (trial 1),0.000153
|
||||||
|
BST,random,insert (trial 2),0.031806
|
||||||
|
BST,random,find (trial 2),0.000286
|
||||||
|
BST,random,delete (trial 2),0.000157
|
||||||
|
BST,random,insert (trial 3),0.031514
|
||||||
|
BST,random,find (trial 3),0.000267
|
||||||
|
BST,random,delete (trial 3),0.000150
|
||||||
|
BST,random,insert (trial 4),0.031758
|
||||||
|
BST,random,find (trial 4),0.000260
|
||||||
|
BST,random,delete (trial 4),0.000144
|
||||||
|
BST,random,insert (trial 5),0.031923
|
||||||
|
BST,random,find (trial 5),0.000262
|
||||||
|
BST,random,delete (trial 5),0.000145
|
||||||
|
BST,random,Insert (avg),0.031700
|
||||||
|
BST,random,Find (avg),0.000270
|
||||||
|
BST,random,Delete (avg),0.000150
|
||||||
|
BST,sorted,insert (trial 1),14.135551
|
||||||
|
BST,sorted,find (trial 1),0.123919
|
||||||
|
BST,sorted,delete (trial 1),0.054104
|
||||||
|
BST,sorted,insert (trial 2),13.781539
|
||||||
|
BST,sorted,find (trial 2),0.126835
|
||||||
|
BST,sorted,delete (trial 2),0.055120
|
||||||
|
BST,sorted,insert (trial 3),15.010563
|
||||||
|
BST,sorted,find (trial 3),0.117841
|
||||||
|
BST,sorted,delete (trial 3),0.056871
|
||||||
|
BST,sorted,insert (trial 4),14.378650
|
||||||
|
BST,sorted,find (trial 4),0.113316
|
||||||
|
BST,sorted,delete (trial 4),0.054129
|
||||||
|
BST,sorted,insert (trial 5),14.285981
|
||||||
|
BST,sorted,find (trial 5),0.112919
|
||||||
|
BST,sorted,delete (trial 5),0.057369
|
||||||
|
BST,sorted,Insert (avg),14.318457
|
||||||
|
BST,sorted,Find (avg),0.118966
|
||||||
|
BST,sorted,Delete (avg),0.055519
|
||||||
|
312
ivankinad/task1/laba1.py
Normal file
312
ivankinad/task1/laba1.py
Normal file
|
|
@ -0,0 +1,312 @@
|
||||||
|
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):
|
||||||
|
"""Ищет узел по имени. Возвращает телефон или None."""
|
||||||
|
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):
|
||||||
|
"""Вычисляет индекс бакета и вызывает ll_insert."""
|
||||||
|
bucket_idx = abs(hash(name)) % len(buckets)
|
||||||
|
buckets[bucket_idx] = ll_insert(buckets[bucket_idx], name, phone)
|
||||||
|
|
||||||
|
def ht_find(buckets, name):
|
||||||
|
"""Вычисляет индекс бакета и вызывает ll_find."""
|
||||||
|
bucket_idx = abs(hash(name)) % len(buckets)
|
||||||
|
return ll_find(buckets[bucket_idx], name)
|
||||||
|
|
||||||
|
def ht_delete(buckets, name):
|
||||||
|
"""Вычисляет индекс бакета и вызывает ll_delete."""
|
||||||
|
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):
|
||||||
|
"""Рекурсивное удаление узла из BST."""
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Сохранение в CSV
|
||||||
|
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):
|
||||||
|
"""
|
||||||
|
Создает графики производительности структур данных.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
plot_data: список кортежей (structure, mode, avg_insert, avg_find, avg_delete)
|
||||||
|
"""
|
||||||
|
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'")
|
||||||
BIN
ivankinad/task1/performance_charts.png
Normal file
BIN
ivankinad/task1/performance_charts.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 180 KiB |
Loading…
Reference in New Issue
Block a user