forked from UNN/2026-rff_mp
349 lines
8.3 KiB
Python
349 lines
8.3 KiB
Python
import random
|
||
import time
|
||
import csv
|
||
import sys
|
||
|
||
sys.setrecursionlimit(10**8)#прикалюха 6 вылетаел
|
||
|
||
def mk(name, phone):
|
||
return {"name": name, "phone": phone}
|
||
|
||
def ll_create_node(record):
|
||
return [record, None]
|
||
|
||
def ll_insert(ll_head, record):
|
||
new_node = ll_create_node(record)
|
||
new_node[1] = ll_head[0]
|
||
ll_head[0] = new_node
|
||
|
||
def ll_find(ll_head, name):
|
||
cur = ll_head[0]
|
||
while cur:
|
||
if cur[0]["name"] == name:
|
||
return cur[0]
|
||
cur = cur[1]
|
||
return None
|
||
|
||
def ll_delete(ll_head, name):
|
||
cur = ll_head[0]
|
||
prev = None
|
||
while cur:
|
||
if cur[0]["name"] == name:
|
||
if prev:
|
||
prev[1] = cur[1]
|
||
else:
|
||
ll_head[0] = cur[1]
|
||
return True
|
||
prev = cur
|
||
cur = cur[1]
|
||
return False
|
||
|
||
def ll_list_all(ll_head):
|
||
res = []
|
||
cur = ll_head[0]
|
||
while cur:
|
||
res.append(cur[0])
|
||
cur = cur[1]
|
||
return res
|
||
|
||
def ht_hash(name, size):
|
||
return hash(name) % size
|
||
|
||
def ht_insert(table, record):
|
||
idx = ht_hash(record["name"], len(table))
|
||
new_node = ll_create_node(record)
|
||
new_node[1] = table[idx]
|
||
table[idx] = new_node
|
||
|
||
def ht_find(table, name):
|
||
idx = ht_hash(name, len(table))
|
||
cur = table[idx]
|
||
while cur:
|
||
if cur[0]["name"] == name:
|
||
return cur[0]
|
||
cur = cur[1]
|
||
return None
|
||
|
||
def ht_delete(table, name):
|
||
idx = ht_hash(name, len(table))
|
||
cur = table[idx]
|
||
prev = None
|
||
while cur:
|
||
if cur[0]["name"] == name:
|
||
if prev:
|
||
prev[1] = cur[1]
|
||
else:
|
||
table[idx] = cur[1]
|
||
return True
|
||
prev = cur
|
||
cur = cur[1]
|
||
return False
|
||
|
||
def ht_list_all(table):
|
||
res = []
|
||
for head in table:
|
||
cur = head
|
||
while cur:
|
||
res.append(cur[0])
|
||
cur = cur[1]
|
||
return res
|
||
|
||
def bst_create_node(record):
|
||
return [record, None, None]
|
||
|
||
def bst_insert(root, record):
|
||
if root is None:
|
||
return bst_create_node(record)
|
||
if record["name"] < root[0]["name"]:
|
||
root[1] = bst_insert(root[1], record)
|
||
elif record["name"] > root[0]["name"]:
|
||
root[2] = bst_insert(root[2], record)
|
||
else:
|
||
root[0] = record
|
||
return root
|
||
|
||
def bst_find(root, name):
|
||
if root is None:
|
||
return None
|
||
if name == root[0]["name"]:
|
||
return root[0]
|
||
elif name < root[0]["name"]:
|
||
return bst_find(root[1], name)
|
||
else:
|
||
return bst_find(root[2], name)
|
||
|
||
def bst_find_min(node):
|
||
while node[1] is not None:
|
||
node = node[1]
|
||
return node
|
||
|
||
def bst_delete(root, name):
|
||
if root is None:
|
||
return None
|
||
if name < root[0]["name"]:
|
||
root[1] = bst_delete(root[1], name)
|
||
elif name > root[0]["name"]:
|
||
root[2] = bst_delete(root[2], name)
|
||
else:
|
||
if root[1] is None:
|
||
return root[2]
|
||
elif root[2] is None:
|
||
return root[1]
|
||
else:
|
||
succ = bst_find_min(root[2])
|
||
root[0] = succ[0]
|
||
root[2] = bst_delete(root[2], succ[0]["name"])
|
||
return root
|
||
|
||
def bst_list_all(root):
|
||
def inorder(node):
|
||
if node is None:
|
||
return []
|
||
return inorder(node[1]) + [node[0]] + inorder(node[2])
|
||
return inorder(root)
|
||
|
||
def tmr(func):
|
||
def wrapper(*args, **kwargs):
|
||
start = time.perf_counter()
|
||
result = func(*args, **kwargs)
|
||
elapsed = time.perf_counter() - start
|
||
return result, elapsed
|
||
return wrapper
|
||
|
||
@tmr
|
||
def ins_ll(ll_head, records):
|
||
for rec in records:
|
||
ll_insert(ll_head, rec)
|
||
|
||
@tmr
|
||
def fnd_ll(ll_head, names):
|
||
for name in names:
|
||
ll_find(ll_head, name)
|
||
|
||
@tmr
|
||
def del_ll(ll_head, names):
|
||
for name in names:
|
||
ll_delete(ll_head, name)
|
||
|
||
@tmr
|
||
def ins_ht(table, records):
|
||
for rec in records:
|
||
ht_insert(table, rec)
|
||
|
||
@tmr
|
||
def fnd_ht(table, names):
|
||
for name in names:
|
||
ht_find(table, name)
|
||
|
||
@tmr
|
||
def del_ht(table, names):
|
||
for name in names:
|
||
ht_delete(table, name)
|
||
|
||
@tmr
|
||
def ins_bst(root, records):
|
||
for rec in records:
|
||
root = bst_insert(root, rec)
|
||
return root
|
||
|
||
@tmr
|
||
def fnd_bst(root, names):
|
||
for name in names:
|
||
bst_find(root, name)
|
||
|
||
@tmr
|
||
def del_bst(root, names):
|
||
for name in names:
|
||
root = bst_delete(root, name)
|
||
return root
|
||
|
||
def gen(n, seed=42):
|
||
random.seed(seed)
|
||
recs = []
|
||
for i in range(n):
|
||
name = f"user_{i:05d}"
|
||
phone = random.randint(1000000, 9999999)
|
||
recs.append(mk(name, phone))
|
||
return recs
|
||
|
||
def prep(recs, ecnt=100, mcnt=10):
|
||
alln = [r["name"] for r in recs]
|
||
ex = random.sample(alln, ecnt)
|
||
ms = [f"none_{i}" for i in range(mcnt)]
|
||
sn = ex + ms
|
||
dn = random.sample(alln, 50)
|
||
return sn, dn
|
||
|
||
def prm(n):
|
||
if n < 2: return False
|
||
if n % 2 == 0: return n == 2
|
||
d = 3
|
||
while d * d <= n:
|
||
if n % d == 0: return False
|
||
d += 2
|
||
return True
|
||
|
||
def nxtprm(n):
|
||
while not prm(n):
|
||
n += 1
|
||
return n
|
||
|
||
def bench(n=10000, rpts=5):
|
||
recs = gen(n)
|
||
shuf = recs.copy()
|
||
random.shuffle(shuf)
|
||
srt = sorted(recs, key=lambda r: r["name"])
|
||
|
||
snms, dnms = prep(recs)
|
||
|
||
htsz = nxtprm(2 * n)
|
||
|
||
exps = [
|
||
{
|
||
"name": "linkedlist",
|
||
"init_empty": lambda: [None],
|
||
"insert": ins_ll,
|
||
"find": fnd_ll,
|
||
"delete": del_ll,
|
||
},
|
||
{
|
||
"name": "hashtable",
|
||
"init_empty": lambda: [None] * htsz,
|
||
"insert": ins_ht,
|
||
"find": fnd_ht,
|
||
"delete": del_ht,
|
||
},
|
||
{
|
||
"name": "bst",
|
||
"init_empty": lambda: None,
|
||
"insert": ins_bst,
|
||
"find": fnd_bst,
|
||
"delete": del_bst,
|
||
},
|
||
]
|
||
|
||
res = []
|
||
|
||
for e in exps:
|
||
sn = e["name"]
|
||
for mn, recs_set in [("shuffled", shuf), ("sorted", srt)]:
|
||
for rp in range(1, rpts + 1):
|
||
st = e["init_empty"]()
|
||
|
||
if sn == "bst":
|
||
st, ti = e["insert"](st, recs_set)
|
||
else:
|
||
_, ti = e["insert"](st, recs_set)
|
||
|
||
_, tf = e["find"](st, snms)
|
||
|
||
if sn == "bst":
|
||
st, td = e["delete"](st, dnms)
|
||
else:
|
||
_, td = e["delete"](st, dnms)
|
||
|
||
res.append([sn, mn, "insert", rp, ti])
|
||
res.append([sn, mn, "find", rp, tf])
|
||
res.append([sn, mn, "delete", rp, td])
|
||
|
||
with open("results.csv", "w", newline="", encoding="utf-8") as f:
|
||
w = csv.writer(f)
|
||
w.writerow(["тип", "режим", "операция", "повтор", "время"])
|
||
w.writerows(res)
|
||
|
||
from collections import defaultdict
|
||
agg = defaultdict(list)
|
||
for row in res:
|
||
k = (row[0], row[1], row[2])
|
||
agg[k].append(row[4])
|
||
print("\n5 повторов в ср:")
|
||
print(f"{'тип':<15} {'режим':<10} {'операция':<10} {'срдений':<10}")
|
||
for k, times in sorted(agg.items()):
|
||
avg = sum(times) / len(times)
|
||
print(f"{k[0]:<15} {k[1]:<10} {k[2]:<10} {avg:<10.6f}")
|
||
|
||
return res, agg
|
||
|
||
def plot(agg):
|
||
try:
|
||
import matplotlib.pyplot as plt
|
||
except ImportError:
|
||
print("матплотлтб скачать")
|
||
return
|
||
|
||
sts = ["linkedlist", "hashtable", "bst"]
|
||
mds = ["shuffled", "sorted"]
|
||
ops = ["insert", "find", "delete"]
|
||
|
||
fig, axes = plt.subplots(1, 3, figsize=(16, 5))
|
||
fig.suptitle("сравенние", fontsize=14)
|
||
|
||
for oi, op in enumerate(ops):
|
||
ax = axes[oi]
|
||
data = []
|
||
for s in sts:
|
||
for m in mds:
|
||
k = (s, m, op)
|
||
avg = sum(agg[k]) / len(agg[k]) if k in agg else 0
|
||
data.append(avg)
|
||
x = range(len(sts))
|
||
width = 0.35
|
||
svals = [data[i*2] for i in range(len(sts))]
|
||
svals2 = [data[i*2+1] for i in range(len(sts))]
|
||
|
||
ax.bar([i - width/2 for i in x], svals, width, label='shuffled')
|
||
ax.bar([i + width/2 for i in x], svals2, width, label='sorted')
|
||
ax.set_xticks(x)
|
||
ax.set_xticklabels(sts)
|
||
ax.set_title(op)
|
||
ax.set_ylabel('время (sec)')
|
||
ax.legend()
|
||
|
||
plt.tight_layout()
|
||
plt.savefig("kortinko.png")
|
||
plt.show()
|
||
print("zibka kortinko.png")
|
||
|
||
if __name__ == "__main__":
|
||
res, agg = bench(n=10000, rpts=5)
|
||
plot(agg) |