2026-rff_mp/ShapovalovKA/docs/data/1Task/t1_3.py

211 lines
7.3 KiB
Python
Raw Normal View History

2026-05-25 08:58:51 +00:00
import random
import time
import csv
import os
# --------------------- Реализация бинарного дерева поиска (итеративная) ---------------------
def bst_insert(root, name, phone):
#Итеративная вставка. Возвращает корень.
new_node = {'name': name, 'phone': phone, 'left': None, 'right': None}
if root is None:
return new_node
current = root
while True:
if name < current['name']:
if current['left'] is None:
current['left'] = new_node
break
else:
current = current['left']
elif name > current['name']:
if current['right'] is None:
current['right'] = new_node
break
else:
current = current['right']
else: # имя уже существует — обновляем телефон
current['phone'] = phone
break
return root
def bst_find(root, name):
#Итеративный поиск. Возвращает phone или None.
current = root
while current:
if name == current['name']:
return current['phone']
elif name < current['name']:
current = current['left']
else:
current = current['right']
return None
def bst_find_min(node):
#Возвращает узел с минимальным ключом в поддереве.
while node['left']:
node = node['left']
return node
def bst_delete(root, name):
#Итеративное удаление. Возвращает новый корень.
# Сначала найдём удаляемый узел и его родителя
parent = None
current = root
while current and current['name'] != name:
parent = current
if name < current['name']:
current = current['left']
else:
current = current['right']
if current is None: # узел не найден
return root
# Случай 1: нет левого потомка
if current['left'] is None:
child = current['right']
# Случай 2: нет правого потомка
elif current['right'] is None:
child = current['left']
# Случай 3: два потомка
else:
# Находим минимальный узел в правом поддереве (преемник)
min_parent = current
min_node = current['right']
while min_node['left']:
min_parent = min_node
min_node = min_node['left']
# Копируем данные из min_node в current
current['name'], current['phone'] = min_node['name'], min_node['phone']
# Удаляем min_node (у него нет левого потомка)
if min_parent['left'] == min_node:
min_parent['left'] = min_node['right']
else:
min_parent['right'] = min_node['right']
return root
# Подсоединяем child к parent
if parent is None:
return child
if parent['left'] == current:
parent['left'] = child
else:
parent['right'] = child
return root
def bst_list_all(root):
#Итеративный симметричный обход (inorder) без рекурсии, используя стек.
result = []
stack = []
current = root
while stack or current:
while current:
stack.append(current)
current = current['left']
current = stack.pop()
result.append((current['name'], current['phone']))
current = current['right']
return result
# --------------------- Функции измерений ---------------------
def generate_data(N=10000):
records = []
for i in range(N):
name = f"User_{i:05d}"
phone = f"8{random.randint(9000000000, 9999999999)}"
records.append((name, phone))
return records
def measure_insert(records):
root = None
start = time.perf_counter()
for name, phone in records:
root = bst_insert(root, name, phone)
end = time.perf_counter()
return end - start
def measure_find(records, test_names):
root = None
for name, phone in records:
root = bst_insert(root, name, phone)
start = time.perf_counter()
for name in test_names:
bst_find(root, name)
end = time.perf_counter()
return end - start
def measure_delete(records, delete_names):
times = []
for name in delete_names:
root = None
for n, p in records:
root = bst_insert(root, n, p)
start = time.perf_counter()
root = bst_delete(root, name)
end = time.perf_counter()
times.append(end - start)
return sum(times) / len(times)
def main():
N = 10000
records = generate_data(N)
records_shuffled = records.copy()
random.shuffle(records_shuffled)
records_sorted = sorted(records, key=lambda x: x[0])
existing_names = random.sample([rec[0] for rec in records], 100)
non_existing = [f"None_{i}" for i in range(10)]
test_names = existing_names + non_existing
delete_names = random.sample([rec[0] for rec in records], 50)
insert_shuffled_avg = 0.0
insert_sorted_avg = 0.0
find_avg = 0.0
delete_avg = 0.0
repeats = 5
for _ in range(repeats):
insert_shuffled_avg += measure_insert(records_shuffled)
insert_sorted_avg += measure_insert(records_sorted)
find_avg += measure_find(records, test_names)
delete_avg += measure_delete(records, delete_names)
insert_shuffled_avg /= repeats
insert_sorted_avg /= repeats
find_avg /= repeats
delete_avg /= repeats
new_rows = [
["Binary tree", "случайный", "вставка (корень)", insert_shuffled_avg],
["Binary tree", "отсортированный", "вставка (корень)", insert_sorted_avg],
["Binary tree", "любой", "поиск 110 записей", find_avg],
["Binary tree", "любой", "удаление 50 записей (среднее)", delete_avg]
]
csv_filename = "results.csv"
file_exists = os.path.isfile(csv_filename)
need_header = False
if file_exists:
with open(csv_filename, 'r', encoding='utf-8-sig') as f:
first_line = f.readline()
if not first_line.startswith("Структура"):
need_header = True
else:
need_header = True
with open(csv_filename, 'a', newline='', encoding='utf-8-sig') as f:
writer = csv.writer(f, delimiter=';')
if need_header:
writer.writerow(["Структура", "Режим", "Операция", "Время (сек)"])
writer.writerows(new_rows)
print("Результаты для двоичного дерева поиска добавлены в", csv_filename)
print(f"Среднее время вставки (случ. порядок): {insert_shuffled_avg:.6f} сек")
print(f"Среднее время вставки (отсорт.): {insert_sorted_avg:.6f} сек")
print(f"Среднее время поиска 110 записей: {find_avg:.6f} сек")
print(f"Среднее время удаления 50 записей: {delete_avg:.6f} сек")
if __name__ == "__main__":
main()