added experiment
This commit is contained in:
parent
77485a5318
commit
bf2dc50479
|
|
@ -161,4 +161,145 @@ def bst_list_all(root):
|
|||
node = stack.pop()
|
||||
result.append((node['name'], node['phone']))
|
||||
node = node['right']
|
||||
return result
|
||||
return result
|
||||
|
||||
"""
|
||||
Экспериментальная часть: замер производительности трёх структур данных.
|
||||
"""
|
||||
|
||||
import time
|
||||
import csv
|
||||
import random
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.setrecursionlimit(30000) # BST с отсортированными данными — глубокая рекурсия
|
||||
|
||||
|
||||
# ── Параметры ──────────────────────────────────────────────────────────────
|
||||
N = 10_000 # размер набора
|
||||
REPEATS = 5 # повторений каждого замера
|
||||
SEARCH_N = 100 # запросов на поиск (существующих)
|
||||
SEARCH_MISS = 10 # запросов на поиск (отсутствующих)
|
||||
DELETE_N = 50 # удалений
|
||||
|
||||
random.seed(42)
|
||||
|
||||
# ── Генерация данных ───────────────────────────────────────────────────────
|
||||
records_sorted = [(f"User_{i:05d}", f"+7-000-{i:07d}") for i in range(N)]
|
||||
records_shuffled = records_sorted[:]
|
||||
random.shuffle(records_shuffled)
|
||||
|
||||
search_names_hit = [records_sorted[i][0] for i in random.sample(range(N), SEARCH_N)]
|
||||
search_names_miss = [f"None_{i:04d}" for i in range(SEARCH_MISS)]
|
||||
search_names = search_names_hit + search_names_miss
|
||||
|
||||
delete_names = [records_sorted[i][0] for i in random.sample(range(N), DELETE_N)]
|
||||
|
||||
# ── Вспомогательные функции ────────────────────────────────────────────────
|
||||
|
||||
def build_ll(records):
|
||||
head = None
|
||||
for name, phone in records:
|
||||
head = ll_insert(head, name, phone)
|
||||
return head
|
||||
|
||||
def build_ht(records):
|
||||
buckets = ht_create()
|
||||
for name, phone in records:
|
||||
ht_insert(buckets, name, phone)
|
||||
return buckets
|
||||
|
||||
def build_bst(records):
|
||||
root = None
|
||||
for name, phone in records:
|
||||
root = bst_insert(root, name, phone)
|
||||
return root
|
||||
|
||||
STRUCTURES = {
|
||||
'LinkedList': {
|
||||
'build': build_ll,
|
||||
'find': ll_find,
|
||||
'delete': lambda ds, name: ll_delete(ds, name), # возвращает новый head
|
||||
'list_all': ll_list_all,
|
||||
'mutable': False, # ll_delete возвращает новую голову
|
||||
},
|
||||
'HashTable': {
|
||||
'build': build_ht,
|
||||
'find': ht_find,
|
||||
'delete': lambda ds, name: ht_delete(ds, name), # in-place, returns None
|
||||
'list_all': ht_list_all,
|
||||
'mutable': True,
|
||||
},
|
||||
'BST': {
|
||||
'build': build_bst,
|
||||
'find': bst_find,
|
||||
'delete': lambda ds, name: bst_delete(ds, name), # возвращает новый корень
|
||||
'list_all': bst_list_all,
|
||||
'mutable': False,
|
||||
},
|
||||
}
|
||||
|
||||
MODES = {
|
||||
'shuffled': records_shuffled,
|
||||
'sorted': records_sorted,
|
||||
}
|
||||
|
||||
# ── Замер ──────────────────────────────────────────────────────────────────
|
||||
|
||||
def measure(fn, *args, repeats=REPEATS):
|
||||
times = []
|
||||
for _ in range(repeats):
|
||||
t0 = time.perf_counter()
|
||||
fn(*args)
|
||||
times.append(time.perf_counter() - t0)
|
||||
return times
|
||||
|
||||
rows = [["structure", "mode", "operation", "run", "time_sec"]]
|
||||
|
||||
for struct_name, ops in STRUCTURES.items():
|
||||
for mode_name, records in MODES.items():
|
||||
print(f" {struct_name} / {mode_name} ...", flush=True)
|
||||
|
||||
# ── А. Вставка ──────────────────────────────────────────────────
|
||||
insert_times = []
|
||||
for run in range(REPEATS):
|
||||
t0 = time.perf_counter()
|
||||
ds = ops['build'](records)
|
||||
insert_times.append(time.perf_counter() - t0)
|
||||
rows.append([struct_name, mode_name, "insert", run + 1, insert_times[-1]])
|
||||
|
||||
# Строим структуру один раз для поиска и удаления
|
||||
ds = ops['build'](records)
|
||||
|
||||
# ── Б. Поиск ────────────────────────────────────────────────────
|
||||
def do_search(ds=ds):
|
||||
for name in search_names:
|
||||
ops['find'](ds, name)
|
||||
|
||||
search_times = measure(do_search)
|
||||
for run, t in enumerate(search_times, 1):
|
||||
rows.append([struct_name, mode_name, "find", run, t])
|
||||
|
||||
# ── В. Удаление ─────────────────────────────────────────────────
|
||||
# Удаление изменяет структуру, поэтому каждый раз пересобираем
|
||||
delete_times = []
|
||||
for run in range(REPEATS):
|
||||
ds2 = ops['build'](records)
|
||||
t0 = time.perf_counter()
|
||||
for name in delete_names:
|
||||
result = ops['delete'](ds2, name)
|
||||
if result is not None: # ll / bst возвращают новую голову/корень
|
||||
ds2 = result
|
||||
delete_times.append(time.perf_counter() - t0)
|
||||
rows.append([struct_name, mode_name, "delete", run + 1, delete_times[-1]])
|
||||
|
||||
print(f" insert avg={sum(insert_times)/REPEATS:.4f}s "
|
||||
f"find avg={sum(search_times)/REPEATS:.4f}s "
|
||||
f"delete avg={sum(delete_times)/REPEATS:.4f}s")
|
||||
|
||||
|
||||
with open("results.csv", "w", newline="", encoding="utf-8") as f:
|
||||
csv.writer(f).writerows(rows)
|
||||
|
||||
print("\nРезультаты сохранены в docs/data/results.csv")
|
||||
Loading…
Reference in New Issue
Block a user