2026-05-16 22:49:59 +00:00
|
|
|
|
# Task 1
|
|
|
|
|
|
import time
|
|
|
|
|
|
import random
|
|
|
|
|
|
import csv
|
|
|
|
|
|
from collections import defaultdict
|
|
|
|
|
|
|
|
|
|
|
|
def ll_insert(head, name, phone):
|
|
|
|
|
|
new = {'name': name, 'phone': phone, 'next': None}
|
|
|
|
|
|
if head is None:
|
|
|
|
|
|
return new
|
|
|
|
|
|
cur = head
|
|
|
|
|
|
while cur:
|
|
|
|
|
|
if cur['name'] == name:
|
|
|
|
|
|
cur['phone'] = phone
|
|
|
|
|
|
return head
|
|
|
|
|
|
if cur['next'] is None:
|
|
|
|
|
|
break
|
|
|
|
|
|
cur = cur['next']
|
|
|
|
|
|
cur['next'] = new
|
|
|
|
|
|
return head
|
|
|
|
|
|
|
|
|
|
|
|
def ll_find(head, name):
|
|
|
|
|
|
cur = head
|
|
|
|
|
|
while cur:
|
|
|
|
|
|
if cur['name'] == name:
|
|
|
|
|
|
return cur['phone']
|
|
|
|
|
|
cur = cur['next']
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def ll_delete(head, name):
|
|
|
|
|
|
if head is None:
|
|
|
|
|
|
return None
|
|
|
|
|
|
if head['name'] == name:
|
|
|
|
|
|
return head['next']
|
|
|
|
|
|
prev = head
|
|
|
|
|
|
cur = head['next']
|
|
|
|
|
|
while cur:
|
|
|
|
|
|
if cur['name'] == name:
|
|
|
|
|
|
prev['next'] = cur['next']
|
|
|
|
|
|
return head
|
|
|
|
|
|
prev = cur
|
|
|
|
|
|
cur = cur['next']
|
|
|
|
|
|
return head
|
|
|
|
|
|
|
|
|
|
|
|
def ll_list_all(head):
|
|
|
|
|
|
rec = []
|
|
|
|
|
|
cur = head
|
|
|
|
|
|
while cur:
|
|
|
|
|
|
rec.append((cur['name'], cur['phone']))
|
|
|
|
|
|
cur = cur['next']
|
|
|
|
|
|
rec.sort(key=lambda x: x[0])
|
|
|
|
|
|
return rec
|
|
|
|
|
|
|
2026-05-17 20:20:06 +00:00
|
|
|
|
# 2. Хеш-таблица
|
|
|
|
|
|
def ht_insert(buckets, name, phone):
|
|
|
|
|
|
idx = hash(name) % len(buckets)
|
|
|
|
|
|
buckets[idx] = ll_insert(buckets[idx], name, phone)
|
|
|
|
|
|
return buckets
|
|
|
|
|
|
|
|
|
|
|
|
def ht_find(buckets, name):
|
|
|
|
|
|
idx = hash(name) % len(buckets)
|
|
|
|
|
|
return ll_find(buckets[idx], name)
|
|
|
|
|
|
|
|
|
|
|
|
def ht_delete(buckets, name):
|
|
|
|
|
|
idx = hash(name) % len(buckets)
|
|
|
|
|
|
buckets[idx] = ll_delete(buckets[idx], name)
|
|
|
|
|
|
return buckets
|
|
|
|
|
|
|
|
|
|
|
|
def ht_list_all(buckets):
|
|
|
|
|
|
rec = []
|
|
|
|
|
|
for b in buckets:
|
|
|
|
|
|
cur = b
|
|
|
|
|
|
while cur:
|
|
|
|
|
|
rec.append((cur['name'], cur['phone']))
|
|
|
|
|
|
cur = cur['next']
|
|
|
|
|
|
rec.sort(key=lambda x: x[0])
|
|
|
|
|
|
return rec
|
|
|
|
|
|
|
2026-05-18 19:11:37 +00:00
|
|
|
|
def bst_insert(root, name, phone):
|
|
|
|
|
|
new = {'name': name, 'phone': phone, 'left': None, 'right': None}
|
|
|
|
|
|
if root is None:
|
|
|
|
|
|
return new
|
|
|
|
|
|
cur = root
|
|
|
|
|
|
while True:
|
|
|
|
|
|
if name < cur['name']:
|
|
|
|
|
|
if cur['left'] is None:
|
|
|
|
|
|
cur['left'] = new
|
|
|
|
|
|
break
|
|
|
|
|
|
cur = cur['left']
|
|
|
|
|
|
elif name > cur['name']:
|
|
|
|
|
|
if cur['right'] is None:
|
|
|
|
|
|
cur['right'] = new
|
|
|
|
|
|
break
|
|
|
|
|
|
cur = cur['right']
|
|
|
|
|
|
else:
|
|
|
|
|
|
cur['phone'] = phone
|
|
|
|
|
|
break
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
|
|
def bst_find(root, name):
|
|
|
|
|
|
cur = root
|
|
|
|
|
|
while cur:
|
|
|
|
|
|
if name == cur['name']:
|
|
|
|
|
|
return cur['phone']
|
|
|
|
|
|
elif name < cur['name']:
|
|
|
|
|
|
cur = cur['left']
|
|
|
|
|
|
else:
|
|
|
|
|
|
cur = cur['right']
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def bst_delete(root, name):
|
|
|
|
|
|
if root is None:
|
|
|
|
|
|
return None
|
|
|
|
|
|
parent = None
|
|
|
|
|
|
cur = root
|
|
|
|
|
|
while cur and cur['name'] != name:
|
|
|
|
|
|
parent = cur
|
|
|
|
|
|
if name < cur['name']:
|
|
|
|
|
|
cur = cur['left']
|
|
|
|
|
|
else:
|
|
|
|
|
|
cur = cur['right']
|
|
|
|
|
|
if cur is None:
|
|
|
|
|
|
return root
|
|
|
|
|
|
# нет детей
|
|
|
|
|
|
if cur['left'] is None and cur['right'] is None:
|
|
|
|
|
|
if parent is None:
|
|
|
|
|
|
return None
|
|
|
|
|
|
if parent['left'] is cur:
|
|
|
|
|
|
parent['left'] = None
|
|
|
|
|
|
else:
|
|
|
|
|
|
parent['right'] = None
|
|
|
|
|
|
return root
|
|
|
|
|
|
# один ребёнок
|
|
|
|
|
|
if cur['left'] is None:
|
|
|
|
|
|
child = cur['right']
|
|
|
|
|
|
elif cur['right'] is None:
|
|
|
|
|
|
child = cur['left']
|
|
|
|
|
|
else:
|
|
|
|
|
|
# два ребёнка ищем минимальный в правом поддереве
|
|
|
|
|
|
succ_parent = cur
|
|
|
|
|
|
succ = cur['right']
|
|
|
|
|
|
while succ['left']:
|
|
|
|
|
|
succ_parent = succ
|
|
|
|
|
|
succ = succ['left']
|
|
|
|
|
|
cur['name'], cur['phone'] = succ['name'], succ['phone']
|
|
|
|
|
|
if succ_parent['left'] is succ:
|
|
|
|
|
|
succ_parent['left'] = succ['right']
|
|
|
|
|
|
else:
|
|
|
|
|
|
succ_parent['right'] = succ['right']
|
|
|
|
|
|
return root
|
|
|
|
|
|
if parent is None:
|
|
|
|
|
|
return child
|
|
|
|
|
|
if parent['left'] is cur:
|
|
|
|
|
|
parent['left'] = child
|
|
|
|
|
|
else:
|
|
|
|
|
|
parent['right'] = child
|
|
|
|
|
|
return root
|
|
|
|
|
|
|
|
|
|
|
|
def bst_list_all(root):
|
|
|
|
|
|
res = []
|
|
|
|
|
|
stack = []
|
|
|
|
|
|
cur = root
|
|
|
|
|
|
while stack or cur:
|
|
|
|
|
|
while cur:
|
|
|
|
|
|
stack.append(cur)
|
|
|
|
|
|
cur = cur['left']
|
|
|
|
|
|
cur = stack.pop()
|
|
|
|
|
|
res.append((cur['name'], cur['phone']))
|
|
|
|
|
|
cur = cur['right']
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
2026-05-16 22:49:59 +00:00
|
|
|
|
def gen_data(N=10000):
|
|
|
|
|
|
data = []
|
|
|
|
|
|
for i in range(N):
|
|
|
|
|
|
name = f"user_{i:06d}"
|
|
|
|
|
|
phone = f"+7-{random.randint(100,999)}-{random.randint(100,999)}-{random.randint(1000,9999)}"
|
|
|
|
|
|
data.append((name, phone))
|
|
|
|
|
|
shuffled = data[:]
|
|
|
|
|
|
random.shuffle(shuffled)
|
|
|
|
|
|
sorted_data = sorted(data, key=lambda x: x[0])
|
|
|
|
|
|
return shuffled, sorted_data
|
|
|
|
|
|
|
|
|
|
|
|
# 5 повторений сохраняем все замеры
|
|
|
|
|
|
def run_test(init_func, ins_func, find_func, del_func, list_func,
|
|
|
|
|
|
shuffled, sorted_data, exist_names, missing_names, del_names):
|
|
|
|
|
|
rows = []
|
|
|
|
|
|
for order, dataset in [('shuffled', shuffled), ('sorted', sorted_data)]:
|
|
|
|
|
|
for rep in range(5):
|
|
|
|
|
|
s = init_func()
|
|
|
|
|
|
# вставка
|
|
|
|
|
|
t1 = time.perf_counter()
|
|
|
|
|
|
for name, phone in dataset:
|
|
|
|
|
|
s = ins_func(s, name, phone)
|
|
|
|
|
|
t2 = time.perf_counter()
|
|
|
|
|
|
rows.append([order, rep+1, 'insert', t2 - t1])
|
|
|
|
|
|
# поиск
|
|
|
|
|
|
t1 = time.perf_counter()
|
|
|
|
|
|
for name in exist_names:
|
|
|
|
|
|
find_func(s, name)
|
|
|
|
|
|
for name in missing_names:
|
|
|
|
|
|
find_func(s, name)
|
|
|
|
|
|
t2 = time.perf_counter()
|
|
|
|
|
|
rows.append([order, rep+1, 'find', t2 - t1])
|
|
|
|
|
|
# удаление
|
|
|
|
|
|
t1 = time.perf_counter()
|
|
|
|
|
|
for name in del_names:
|
|
|
|
|
|
s = del_func(s, name)
|
|
|
|
|
|
t2 = time.perf_counter()
|
|
|
|
|
|
rows.append([order, rep+1, 'delete', t2 - t1])
|
|
|
|
|
|
|
|
|
|
|
|
t1 = time.perf_counter()
|
|
|
|
|
|
list_func(s)
|
|
|
|
|
|
t2 = time.perf_counter()
|
|
|
|
|
|
rows.append([order, rep+1, 'list_all', t2 - t1])
|
|
|
|
|
|
return rows
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
N = 10000
|
|
|
|
|
|
print(f"Генерация {N} записей...")
|
|
|
|
|
|
shuffled, sorted_data = gen_data(N)
|
|
|
|
|
|
|
|
|
|
|
|
exist_names = [name for name, _ in shuffled[:100]]
|
|
|
|
|
|
missing_names = [f"none_{i}" for i in range(10)]
|
|
|
|
|
|
all_names = [name for name, _ in shuffled]
|
|
|
|
|
|
del_names = random.sample(all_names, 50)
|
|
|
|
|
|
|
|
|
|
|
|
all_rows = [] # для CSV
|
|
|
|
|
|
|
|
|
|
|
|
print("Связный список...")
|
|
|
|
|
|
rows = run_test(lambda: None, ll_insert, ll_find, ll_delete, ll_list_all,
|
|
|
|
|
|
shuffled, sorted_data, exist_names, missing_names, del_names)
|
|
|
|
|
|
for r in rows:
|
|
|
|
|
|
all_rows.append(['LinkedList'] + r)
|
|
|
|
|
|
|
2026-05-17 20:20:06 +00:00
|
|
|
|
print("Хеш-таблица...")
|
|
|
|
|
|
rows = run_test(lambda: [None]*2000, ht_insert, ht_find, ht_delete, ht_list_all,
|
|
|
|
|
|
shuffled, sorted_data, exist_names, missing_names, del_names)
|
|
|
|
|
|
for r in rows:
|
|
|
|
|
|
all_rows.append(['HashTable'] + r)
|
|
|
|
|
|
|
2026-05-18 19:11:37 +00:00
|
|
|
|
# бинарное дерево
|
|
|
|
|
|
print("Бинарное дерево...")
|
|
|
|
|
|
rows = run_test(lambda: None, bst_insert, bst_find, bst_delete, bst_list_all,
|
|
|
|
|
|
shuffled, sorted_data, exist_names, missing_names, del_names)
|
|
|
|
|
|
for r in rows:
|
|
|
|
|
|
all_rows.append(['BST'] + r)
|
|
|
|
|
|
|
|
|
|
|
|
# запись в CSV
|
2026-05-16 22:49:59 +00:00
|
|
|
|
with open('results.csv', 'w', newline='', encoding='utf-8') as f:
|
|
|
|
|
|
writer = csv.writer(f)
|
|
|
|
|
|
writer.writerow(['Структура', 'Порядок', 'Повторение', 'Операция', 'Время (с)'])
|
|
|
|
|
|
writer.writerows(all_rows)
|
|
|
|
|
|
|
|
|
|
|
|
print("Все замеры сохранены в results.csv")
|
|
|
|
|
|
|
|
|
|
|
|
# Подсчёт и вывод средних
|
|
|
|
|
|
avg = defaultdict(list)
|
|
|
|
|
|
for row in all_rows:
|
|
|
|
|
|
struct, order, rep, op, t = row
|
|
|
|
|
|
avg[(struct, order, op)].append(t)
|
|
|
|
|
|
print("\nСредние значения (5 запусков):")
|
|
|
|
|
|
print(f"{'Структура':<12} {'Порядок':<10} {'Вставка':>10} {'Поиск':>10} {'Удаление':>10} {'ListAll':>10}")
|
2026-05-18 19:11:37 +00:00
|
|
|
|
for struct in ['LinkedList', 'HashTable', 'BST']:
|
2026-05-16 22:49:59 +00:00
|
|
|
|
for order in ['shuffled', 'sorted']:
|
|
|
|
|
|
row = [struct, order]
|
|
|
|
|
|
for op in ['insert', 'find', 'delete', 'list_all']:
|
|
|
|
|
|
vals = avg[(struct, order, op)]
|
|
|
|
|
|
avg_val = sum(vals)/len(vals)
|
|
|
|
|
|
row.append(f"{avg_val:.5f}")
|
|
|
|
|
|
print(f"{row[0]:<12} {row[1]:<10} {row[2]:>10} {row[3]:>10} {row[4]:>10} {row[5]:>10}")
|
2026-05-18 19:11:37 +00:00
|
|
|
|
print("\nГотово!!!!!.")
|