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()