2026-rff_mp/MochalovAE/docs/data/1.py/benchmark.py

405 lines
12 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 time
import random
import csv
import os
def create_node(name, phone):
return {'name': name, 'phone': phone, 'next': None}
def ll_insert(head, name, phone):
if head is None:
return create_node(name, phone)
if head['name'] == name:
head['phone'] = phone
return head
current = head
while current['next'] is not None:
if current['next']['name'] == name:
current['next']['phone'] = phone
return head
current = current['next']
current['next'] = create_node(name, phone)
return head
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):
if head is None:
return None
if head['name'] == name:
return head['next']
current = head
while current['next'] is not None:
if current['next']['name'] == name:
current['next'] = current['next']['next']
return head
current = current['next']
return head
def ll_list_all(head):
records = []
current = head
while current is not None:
records.append((current['name'], current['phone']))
current = current['next']
records.sort(key=lambda x: x[0])
return records
def hash_function(name, table_size):
hash_value = 0
for char in name:
hash_value = (hash_value * 31 + ord(char)) % table_size
return hash_value
def create_hash_table(size=1000):
return [None] * size
def ht_insert(buckets, name, phone):
index = hash_function(name, len(buckets))
buckets[index] = ll_insert(buckets[index], name, phone)
return buckets
def ht_find(buckets, name):
index = hash_function(name, len(buckets))
return ll_find(buckets[index], name)
def ht_delete(buckets, name):
index = hash_function(name, len(buckets))
buckets[index] = ll_delete(buckets[index], name)
return buckets
def ht_list_all(buckets):
all_records = []
for bucket in buckets:
if bucket is not None:
records = ll_list_all(bucket)
all_records.extend(records)
all_records.sort(key=lambda x: x[0])
return all_records
def bst_create_node(name, phone):
return {
'name': name,
'phone': phone,
'left': None,
'right': None
}
def bst_insert(root, name, phone):
if root is None:
return bst_create_node(name, phone)
current = root
while True:
if name < current['name']:
if current['left'] is None:
current['left'] = bst_create_node(name, phone)
return root
current = current['left']
elif name > current['name']:
if current['right'] is None:
current['right'] = bst_create_node(name, phone)
return root
current = current['right']
else:
current['phone'] = phone
return root
def bst_find(root, name):
current = root
while current is not None:
if name == current['name']:
return current['phone']
elif name < current['name']:
current = current['left']
else:
current = current['right']
return None
def bst_find_min(node):
current = node
while current['left'] is not None:
current = current['left']
return current
def bst_delete(root, name):
if root is None:
return None
if name < root['name']:
root['left'] = bst_delete(root['left'], name)
return root
elif name > root['name']:
root['right'] = bst_delete(root['right'], name)
return root
if root['left'] is None:
return root['right']
elif root['right'] is None:
return root['left']
min_node = bst_find_min(root['right'])
root['name'] = min_node['name']
root['phone'] = min_node['phone']
root['right'] = bst_delete(root['right'], min_node['name'])
return root
def bst_inorder_collect(root, records):
stack = []
current = root
while stack or current:
while current is not None:
stack.append(current)
current = current['left']
current = stack.pop()
records.append((current['name'], current['phone']))
current = current['right']
def bst_list_all(root):
records = []
bst_inorder_collect(root, records)
return records
def generate_test_data(n=1000):
names = []
for i in range(n):
name = f"User_{i:06d}"
phone = f"+7-999-{random.randint(1000000, 9999999)}"
names.append((name, phone))
shuffled = names.copy()
random.shuffle(shuffled)
sorted_records = sorted(names, key=lambda x: x[0])
return shuffled, sorted_records
def run_insert_benchmark(struct_type, data, struct_params=None):
if struct_type == "LinkedList":
head = None
start = time.perf_counter()
for name, phone in data:
head = ll_insert(head, name, phone)
end = time.perf_counter()
return end - start, head
elif struct_type == "HashTable":
size = struct_params.get('size', 1000) if struct_params else 1000
buckets = create_hash_table(size)
start = time.perf_counter()
for name, phone in data:
buckets = ht_insert(buckets, name, phone)
end = time.perf_counter()
return end - start, buckets
elif struct_type == "BST":
root = None
start = time.perf_counter()
for name, phone in data:
root = bst_insert(root, name, phone)
end = time.perf_counter()
return end - start, root
def run_find_benchmark(struct, struct_type, existing_names, non_existing_names):
start = time.perf_counter()
for name in existing_names:
if struct_type == "LinkedList":
result = ll_find(struct, name)
elif struct_type == "HashTable":
result = ht_find(struct, name)
elif struct_type == "BST":
result = bst_find(struct, name)
for name in non_existing_names:
if struct_type == "LinkedList":
result = ll_find(struct, name)
elif struct_type == "HashTable":
result = ht_find(struct, name)
elif struct_type == "BST":
result = bst_find(struct, name)
end = time.perf_counter()
return end - start
def run_delete_benchmark(struct, struct_type, names_to_delete):
start = time.perf_counter()
for name in names_to_delete:
if struct_type == "LinkedList":
struct = ll_delete(struct, name)
elif struct_type == "HashTable":
struct = ht_delete(struct, name)
elif struct_type == "BST":
struct = bst_delete(struct, name)
end = time.perf_counter()
return end - start, struct
def run_experiment(n_records=1000, n_find=100, n_delete=50, n_repeats=3):
print("Генерация тестовых данных...")
shuffled_data, sorted_data = generate_test_data(n_records)
all_names = [name for name, _ in shuffled_data]
find_names = random.sample(all_names, min(n_find, len(all_names)))
delete_names = random.sample(all_names, min(n_delete, len(all_names)))
non_existing = [f"None_{i}" for i in range(10)]
results = []
structures = ["LinkedList", "HashTable", "BST"]
modes = ["random", "sorted"]
print("\nНачало эксперимента...")
print("=" * 80)
for struct_type in structures:
for mode in modes:
data = shuffled_data if mode == "random" else sorted_data
mode_rus = "случайный" if mode == "random" else "отсортированный"
print(f"\nТестирование: {struct_type}, режим: {mode_rus}")
for repeat in range(n_repeats):
print(f" Повторение {repeat + 1}/{n_repeats}")
insert_time, struct = run_insert_benchmark(
struct_type, data,
{'size': n_records} if struct_type == "HashTable" else None
)
results.append([
struct_type, mode_rus, "вставка", repeat + 1, insert_time
])
find_time = run_find_benchmark(
struct, struct_type, find_names, non_existing
)
results.append([
struct_type, mode_rus, "поиск", repeat + 1, find_time
])
delete_time, struct = run_delete_benchmark(
struct, struct_type, delete_names
)
results.append([
struct_type, mode_rus, "удаление", repeat + 1, delete_time
])
return results
def save_results_to_csv(results, filename="docs/data/results.csv"):
os.makedirs("docs/data", exist_ok=True)
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(["Структура", "Режим", "Операция", "Повторение", "Время (сек)"])
writer.writerows(results)
print(f"\nРезультаты сохранены в {filename}")
def print_statistics(results):
print("\n" + "=" * 80)
print("СТАТИСТИКА РЕЗУЛЬТАТОВ")
print("=" * 80)
stats = {}
for row in results:
struct, mode, op, _, time_val = row
key = (struct, mode, op)
if key not in stats:
stats[key] = []
stats[key].append(time_val)
for (struct, mode, op), times in stats.items():
avg_time = sum(times) / len(times)
min_time = min(times)
max_time = max(times)
print(f"\n{struct} - {mode} - {op}:")
print(f" Среднее: {avg_time:.6f} сек")
print(f" Мин: {min_time:.6f} сек")
print(f" Макс: {max_time:.6f} сек")
def verify_correctness():
print("\n" + "=" * 80)
print("ПРОВЕРКА КОРРЕКТНОСТИ РАБОТЫ")
print("=" * 80)
test_data = [
("Alice", "123-456"),
("Bob", "789-012"),
("Charlie", "345-678"),
("Alice", "999-999"),
]
structures = {
"LinkedList": (None, ll_insert, ll_find, ll_delete, ll_list_all),
"HashTable": (create_hash_table(10), ht_insert, ht_find, ht_delete, ht_list_all),
"BST": (None, bst_insert, bst_find, bst_delete, bst_list_all)
}
for name, (struct, insert_func, find_func, delete_func, list_func) in structures.items():
print(f"\n{name}:")
for n, p in test_data:
struct = insert_func(struct, n, p)
print(f" Поиск Alice: {find_func(struct, 'Alice')}")
print(f" Поиск Bob: {find_func(struct, 'Bob')}")
print(f" Поиск Unknown: {find_func(struct, 'Unknown')}")
struct = delete_func(struct, "Bob")
print(f" После удаления Bob: {find_func(struct, 'Bob')}")
all_records = list_func(struct)
print(f" Все записи: {all_records}")
def main():
print("ТЕЛЕФОННЫЙ СПРАВОЧНИК - СРАВНЕНИЕ СТРУКТУР ДАННЫХ")
print("=" * 80)
verify_correctness()
print("\n" + "=" * 80)
print("ЗАПУСК ЭКСПЕРИМЕНТА")
print("=" * 80)
N_RECORDS = 1000
N_FIND = 100
N_DELETE = 50
N_REPEATS = 3
print(f"\nПараметры эксперимента:")
print(f" Количество записей: {N_RECORDS}")
print(f" Поиск: {N_FIND} существующих + 10 отсутствующих")
print(f" Удаление: {N_DELETE} записей")
print(f" Повторений: {N_REPEATS}")
results = run_experiment(N_RECORDS, N_FIND, N_DELETE, N_REPEATS)
save_results_to_csv(results)
print_statistics(results)
print("\n" + "=" * 80)
print("ЭКСПЕРИМЕНТ ЗАВЕРШЕН")
print("=" * 80)
if __name__ == "__main__":
main()