Merge pull request '[1] задание 1 с отчётом' (#261) from kornevma/2026-rff_mp:kornevma_z1 into develop

Reviewed-on: UNN/2026-rff_mp#261
This commit is contained in:
AndreyUrs 2026-05-30 11:24:56 +00:00
commit 77c6985b53
4 changed files with 500 additions and 0 deletions

349
kornevma/docs/1/main.py Normal file
View File

@ -0,0 +1,349 @@
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)

BIN
kornevma/docs/kortinko.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

60
kornevma/docs/report1.txt Normal file
View File

@ -0,0 +1,60 @@
Отчёт по экспериментальному сравнению структур данных телефонного справочника
1. Условия эксперимента
Реализованы три структуры для хранения записей вида {name, phone}:
односвязный список (вставка в голову);
хеш-таблица с цепочками (размер таблицы ~ 2N, простое число, хеш-функция hash(name) % size);
двоичное дерево поиска без балансировки.
Измерялось время выполнения операций вставки N = 10000 записей, поиска 110 имён (100 существующих + 10 несуществующих) и удаления 50 случайных записей.
Эксперименты проводились для двух вариантов порядка входных данных:
shuffled случайный порядок имён;
sorted имена, отсортированные по алфавиту.
Каждый замер повторялся 5 раз, результаты усреднены.
Полученные средние значения (фрагмент):
Структура Режим Вставка (сек) Поиск (сек) Удаление (сек)
LinkedList shuffled ~0.003 ~0.100 ~0.056
LinkedList sorted ~0.003 ~0.063 ~0.038
HashTable shuffled ~0.008 ~0.00006 ~0.00004
HashTable sorted ~0.006 ~0.00008 ~0.00003
BST shuffled ~0.055 ~0.0005 ~0.00027
BST sorted ~23.997 ~0.212 ~0.129
Точные числа см. в файле results.csv
2. Сравнительный анализ
2.1. Влияние порядка данных на BST: деградация до O(n)
На shuffled-данных дерево строится относительно сбалансированным, и операции выполняются в среднем за O(log N).
На sorted-данных каждая следующая вставка попадает строго в правого потомка, и дерево вырождается в линейный список. Глубина рекурсии достигает N = 10000, что приводит к:
колоссальному росту времени вставки (с ~0.055 сек до ~24 сек);
значительному замедлению поиска и удаления (с ~0.0005 сек до ~0.21 сек и с ~0.00027 сек до ~0.13 сек соответственно).
Причина — рекурсивные функции вынуждены обходить все N узлов, превращая логарифмическую сложность в линейную. Практический вывод: использовать несбалансированное BST можно только при гарантированно случайном порядке поступающих ключей, иначе необходимы самобалансирующиеся варианты (AVL, красно-чёрное дерево).
2.2. Почему хеш-таблица почти не чувствительна к порядку
Хеш-функция равномерно распределяет ключи по корзинам независимо от порядка поступления. Операции вставки, поиска и удаления сводятся к вычислению хеша и проходу по очень короткой цепочке (в среднем O(1)). Время вставки в отсортированном наборе даже чуть меньше (0.006 сек против 0.008 сек), что объясняется меньшим количеством коллизий при последовательном поступлении близких имён (хотя разница несущественна). Поиск и удаление занимают доли миллисекунды и практически не зависят от размера набора в исследованном диапазоне. Хеш-таблица демонстрирует наилучшую устойчивость к любым шаблонам входных данных при условии хорошей хеш-функции и адекватного размера.
2.3. Почему связный список всегда медленен при поиске
В односвязном списке единственный способ найти элемент — линейный проход от головы к хвосту. Среднее время поиска — O(N), то есть пропорционально количеству записей. В эксперименте при 10000 записей и поиске 110 имён время составило около 0.1 сек, что на три порядка хуже, чем у хеш-таблицы, и на два порядка хуже, чем у сбалансированного BST. Режим sorted/shuffled влияет слабо (для списка порядок вставки не меняет структуру). Медленный поиск — фундаментальное ограничение связного списка.
2.4. Удаление в каждой структуре
Связный список: удаление требует поиска элемента (O(N)) и изменения ссылки у предыдущего узла. Время удаления соизмеримо с поиском (0.0380.056 сек).
Хеш-таблица: удаление выполняется за O(1) в среднем — вычисление индекса, поиск в цепочке (очень короткой) и изменение ссылок. Время минимально (~0.00004 сек).
BST: удаление узла с двумя потомками требует поиска минимального элемента в правом поддереве. На сбалансированных данных (shuffled) время ~0.00027 сек. На вырожденных (sorted) удаление замедляется до 0.13 сек из-за необходимости обходить длинные цепочки.
3. Выводы и практические рекомендации
Если преобладают частые поиск и вставка, а порядок данных не важен оптимальный выбор хеш-таблица. Она обеспечивает константное среднее время операций и нечувствительна к порядку поступления ключей. Идеально для телефонного справочника, кешей, словарей.
Если требуется хранить данные в отсортированном виде и нужны операции типа «найти следующий/предыдущий» подходит BST, но обязательно самобалансирующееся (например, АВЛ или красно-чёрное дерево). Несбалансированное BST применимо только при случайном порядке вставки; иначе деградация до O(n) делает его бесполезным.
Связный список стоит использовать лишь в случаях, когда операции поиска редки, а основные действия — добавление/удаление в начале или в середине списка при известной позиции. Для телефонного справочника он практически непригоден из-за линейного времени поиска.
Таким образом, для типового приложения с преимущественно операциями поиска и вставки (например, адресная книга в мобильном телефоне) лучшим решением является хеш-таблица. Если же функциональность требует получения отсортированного списка контактов или диапазонных запросов, разумно применять сбалансированное дерево поиска.

91
kornevma/docs/results.csv Normal file
View File

@ -0,0 +1,91 @@
тип,режим,операция,повтор,время
linkedlist,shuffled,insert,1,0.00348759995540604
linkedlist,shuffled,find,1,0.10299369995482266
linkedlist,shuffled,delete,1,0.06881969998357818
linkedlist,shuffled,insert,2,0.002795599983073771
linkedlist,shuffled,find,2,0.11420650000218302
linkedlist,shuffled,delete,2,0.050943999958690256
linkedlist,shuffled,insert,3,0.003374699968844652
linkedlist,shuffled,find,3,0.09485340001992881
linkedlist,shuffled,delete,3,0.04981170000974089
linkedlist,shuffled,insert,4,0.002937599958386272
linkedlist,shuffled,find,4,0.0926941999932751
linkedlist,shuffled,delete,4,0.04564540000865236
linkedlist,shuffled,insert,5,0.0032468000426888466
linkedlist,shuffled,find,5,0.09445199999026954
linkedlist,shuffled,delete,5,0.06562509998911992
linkedlist,sorted,insert,1,0.004829699988476932
linkedlist,sorted,find,1,0.05208860000129789
linkedlist,sorted,delete,1,0.06792090000817552
linkedlist,sorted,insert,2,0.0030329000437632203
linkedlist,sorted,find,2,0.09589699999196455
linkedlist,sorted,delete,2,0.024623799952678382
linkedlist,sorted,insert,3,0.0023055000347085297
linkedlist,sorted,find,3,0.05262780003249645
linkedlist,sorted,delete,3,0.035465800028759986
linkedlist,sorted,insert,4,0.003455400001257658
linkedlist,sorted,find,4,0.06551479996414855
linkedlist,sorted,delete,4,0.0368536000023596
linkedlist,sorted,insert,5,0.0036825999850407243
linkedlist,sorted,find,5,0.05081029998837039
linkedlist,sorted,delete,5,0.02609110000776127
hashtable,shuffled,insert,1,0.008456900017336011
hashtable,shuffled,find,1,7.070001447573304e-05
hashtable,shuffled,delete,1,3.9300008211284876e-05
hashtable,shuffled,insert,2,0.0068731000064872205
hashtable,shuffled,find,2,6.079999729990959e-05
hashtable,shuffled,delete,2,3.4599972423166037e-05
hashtable,shuffled,insert,3,0.008831500017549843
hashtable,shuffled,find,3,6.859999848529696e-05
hashtable,shuffled,delete,3,5.959998816251755e-05
hashtable,shuffled,insert,4,0.009147099975962192
hashtable,shuffled,find,4,5.989999044686556e-05
hashtable,shuffled,delete,4,3.470003139227629e-05
hashtable,shuffled,insert,5,0.006436199997551739
hashtable,shuffled,find,5,4.67000063508749e-05
hashtable,shuffled,delete,5,2.6500027161091566e-05
hashtable,sorted,insert,1,0.0056028999970294535
hashtable,sorted,find,1,7.159996312111616e-05
hashtable,sorted,delete,1,3.060000017285347e-05
hashtable,sorted,insert,2,0.006678299978375435
hashtable,sorted,find,2,0.00012290000449866056
hashtable,sorted,delete,2,3.4299970138818026e-05
hashtable,sorted,insert,3,0.005322600016370416
hashtable,sorted,find,3,4.8499961849302053e-05
hashtable,sorted,delete,3,2.600002335384488e-05
hashtable,sorted,insert,4,0.006450399989262223
hashtable,sorted,find,4,7.379997987300158e-05
hashtable,sorted,delete,4,4.780001472681761e-05
hashtable,sorted,insert,5,0.0060063999844715
hashtable,sorted,find,5,5.689996760338545e-05
hashtable,sorted,delete,5,3.120000474154949e-05
bst,shuffled,insert,1,0.05349189997650683
bst,shuffled,find,1,0.0005713000427931547
bst,shuffled,delete,1,0.0002283000503666699
bst,shuffled,insert,2,0.05809580005006865
bst,shuffled,find,2,0.00046800001291558146
bst,shuffled,delete,2,0.00030310003785416484
bst,shuffled,insert,3,0.05402979999780655
bst,shuffled,find,3,0.0005937999812886119
bst,shuffled,delete,3,0.0002316000172868371
bst,shuffled,insert,4,0.0533465999760665
bst,shuffled,find,4,0.000450699997600168
bst,shuffled,delete,4,0.00031700002728030086
bst,shuffled,insert,5,0.05407660000491887
bst,shuffled,find,5,0.0004341000458225608
bst,shuffled,delete,5,0.0002673999988473952
bst,sorted,insert,1,24.01944399997592
bst,sorted,find,1,0.2082300999900326
bst,sorted,delete,1,0.11376300000119954
bst,sorted,insert,2,24.020037700014655
bst,sorted,find,2,0.21519700001226738
bst,sorted,delete,2,0.1168955999892205
bst,sorted,insert,3,23.98331290000351
bst,sorted,find,3,0.20412800001213327
bst,sorted,delete,3,0.16615210002055392
bst,sorted,insert,4,24.231940899975598
bst,sorted,find,4,0.2066795999999158
bst,sorted,delete,4,0.13191749999532476
bst,sorted,insert,5,23.72923769999761
bst,sorted,find,5,0.22344960004556924
bst,sorted,delete,5,0.11515349999535829
1 тип режим операция повтор время
2 linkedlist shuffled insert 1 0.00348759995540604
3 linkedlist shuffled find 1 0.10299369995482266
4 linkedlist shuffled delete 1 0.06881969998357818
5 linkedlist shuffled insert 2 0.002795599983073771
6 linkedlist shuffled find 2 0.11420650000218302
7 linkedlist shuffled delete 2 0.050943999958690256
8 linkedlist shuffled insert 3 0.003374699968844652
9 linkedlist shuffled find 3 0.09485340001992881
10 linkedlist shuffled delete 3 0.04981170000974089
11 linkedlist shuffled insert 4 0.002937599958386272
12 linkedlist shuffled find 4 0.0926941999932751
13 linkedlist shuffled delete 4 0.04564540000865236
14 linkedlist shuffled insert 5 0.0032468000426888466
15 linkedlist shuffled find 5 0.09445199999026954
16 linkedlist shuffled delete 5 0.06562509998911992
17 linkedlist sorted insert 1 0.004829699988476932
18 linkedlist sorted find 1 0.05208860000129789
19 linkedlist sorted delete 1 0.06792090000817552
20 linkedlist sorted insert 2 0.0030329000437632203
21 linkedlist sorted find 2 0.09589699999196455
22 linkedlist sorted delete 2 0.024623799952678382
23 linkedlist sorted insert 3 0.0023055000347085297
24 linkedlist sorted find 3 0.05262780003249645
25 linkedlist sorted delete 3 0.035465800028759986
26 linkedlist sorted insert 4 0.003455400001257658
27 linkedlist sorted find 4 0.06551479996414855
28 linkedlist sorted delete 4 0.0368536000023596
29 linkedlist sorted insert 5 0.0036825999850407243
30 linkedlist sorted find 5 0.05081029998837039
31 linkedlist sorted delete 5 0.02609110000776127
32 hashtable shuffled insert 1 0.008456900017336011
33 hashtable shuffled find 1 7.070001447573304e-05
34 hashtable shuffled delete 1 3.9300008211284876e-05
35 hashtable shuffled insert 2 0.0068731000064872205
36 hashtable shuffled find 2 6.079999729990959e-05
37 hashtable shuffled delete 2 3.4599972423166037e-05
38 hashtable shuffled insert 3 0.008831500017549843
39 hashtable shuffled find 3 6.859999848529696e-05
40 hashtable shuffled delete 3 5.959998816251755e-05
41 hashtable shuffled insert 4 0.009147099975962192
42 hashtable shuffled find 4 5.989999044686556e-05
43 hashtable shuffled delete 4 3.470003139227629e-05
44 hashtable shuffled insert 5 0.006436199997551739
45 hashtable shuffled find 5 4.67000063508749e-05
46 hashtable shuffled delete 5 2.6500027161091566e-05
47 hashtable sorted insert 1 0.0056028999970294535
48 hashtable sorted find 1 7.159996312111616e-05
49 hashtable sorted delete 1 3.060000017285347e-05
50 hashtable sorted insert 2 0.006678299978375435
51 hashtable sorted find 2 0.00012290000449866056
52 hashtable sorted delete 2 3.4299970138818026e-05
53 hashtable sorted insert 3 0.005322600016370416
54 hashtable sorted find 3 4.8499961849302053e-05
55 hashtable sorted delete 3 2.600002335384488e-05
56 hashtable sorted insert 4 0.006450399989262223
57 hashtable sorted find 4 7.379997987300158e-05
58 hashtable sorted delete 4 4.780001472681761e-05
59 hashtable sorted insert 5 0.0060063999844715
60 hashtable sorted find 5 5.689996760338545e-05
61 hashtable sorted delete 5 3.120000474154949e-05
62 bst shuffled insert 1 0.05349189997650683
63 bst shuffled find 1 0.0005713000427931547
64 bst shuffled delete 1 0.0002283000503666699
65 bst shuffled insert 2 0.05809580005006865
66 bst shuffled find 2 0.00046800001291558146
67 bst shuffled delete 2 0.00030310003785416484
68 bst shuffled insert 3 0.05402979999780655
69 bst shuffled find 3 0.0005937999812886119
70 bst shuffled delete 3 0.0002316000172868371
71 bst shuffled insert 4 0.0533465999760665
72 bst shuffled find 4 0.000450699997600168
73 bst shuffled delete 4 0.00031700002728030086
74 bst shuffled insert 5 0.05407660000491887
75 bst shuffled find 5 0.0004341000458225608
76 bst shuffled delete 5 0.0002673999988473952
77 bst sorted insert 1 24.01944399997592
78 bst sorted find 1 0.2082300999900326
79 bst sorted delete 1 0.11376300000119954
80 bst sorted insert 2 24.020037700014655
81 bst sorted find 2 0.21519700001226738
82 bst sorted delete 2 0.1168955999892205
83 bst sorted insert 3 23.98331290000351
84 bst sorted find 3 0.20412800001213327
85 bst sorted delete 3 0.16615210002055392
86 bst sorted insert 4 24.231940899975598
87 bst sorted find 4 0.2066795999999158
88 bst sorted delete 4 0.13191749999532476
89 bst sorted insert 5 23.72923769999761
90 bst sorted find 5 0.22344960004556924
91 bst sorted delete 5 0.11515349999535829