2026-rff_mp/soldatkinao/lab1/task-1.py

271 lines
8.2 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.

# 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
# 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
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
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)
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)
# бинарное дерево
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
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}")
for struct in ['LinkedList', 'HashTable', 'BST']:
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}")
print("\nГотово!!!!!.")