from MP_records import records import random as rd import time import csv import codecs import sys sys.setrecursionlimit(15000) # ---------- Binary Search Tree ---------- # Узел: # { # "name": name, # "phone": phone, # "left": None, # "right": None # } def bst_insert(root, name, phone): """ Вставляет новую запись или обновляет телефон по имени. Возвращает корень дерева. """ if root is None: return { "name": name, "phone": phone, "left": None, "right": None } if name == root["name"]: root["phone"] = phone elif name < root["name"]: root["left"] = bst_insert(root["left"], name, phone) else: root["right"] = bst_insert(root["right"], name, phone) return root def bst_find(root, name): """ Поиск телефона по имени. """ if root is None: return None if name == root["name"]: return root["phone"] if name < root["name"]: return bst_find(root["left"], name) return bst_find(root["right"], name) def bst_find_min(node): """ Возвращает узел с минимальным именем. """ current = node while current["left"] is not None: current = current["left"] return current def bst_delete(root, name): """ Удаляет запись по имени. Возвращает новый корень дерева. """ if root is None: return None if name < root["name"]: root["left"] = bst_delete(root["left"], name) elif name > root["name"]: root["right"] = bst_delete(root["right"], name) else: # Узел без левого потомка if root["left"] is None: return root["right"] # Узел без правого потомка if root["right"] is None: return root["left"] # Узел с двумя потомками successor = bst_find_min(root["right"]) root["name"] = successor["name"] root["phone"] = successor["phone"] root["right"] = bst_delete(root["right"], successor["name"]) return root def bst_inorder(root, result): """ Центрированный обход дерева. """ if root is None: return bst_inorder(root["left"], result) result.append((root["name"], root["phone"])) bst_inorder(root["right"], result) def bst_list_all(root): """ Возвращает список записей в отсортированном порядке. """ result = [] bst_inorder(root, result) return result # ---------- Benchmark helpers ---------- def build_bst(records_list): root = None for name, phone in records_list: root = bst_insert(root, name, phone) return root def measure_bst(records_list, mode_name, repeats=5): rows = [] insertion_times = [] finding_times = [] deletion_times = [] for run_number in range(1, repeats + 1): data = records_list[:] if mode_name == "случайный": rd.shuffle(data) # А. Вставка root = None start = time.perf_counter() for name, phone in data: root = bst_insert(root, name, phone) end = time.perf_counter() insertion_time = end - start insertion_times.append(insertion_time) # Б. Поиск existing_names = [name for name, phone in rd.sample(data, 100)] missing_names = [f"None_{i}" for i in range(10)] search_names = existing_names + missing_names rd.shuffle(search_names) start = time.perf_counter() for name in search_names: bst_find(root, name) end = time.perf_counter() finding_time = end - start finding_times.append(finding_time) # В. Удаление delete_names = rd.sample(existing_names, 50) start = time.perf_counter() for name in delete_names: root = bst_delete(root, name) end = time.perf_counter() deletion_time = end - start deletion_times.append(deletion_time) rows.append(["BinarySearchTree", mode_name, "вставка", run_number, insertion_time]) rows.append(["BinarySearchTree", mode_name, "поиск", run_number, finding_time]) rows.append(["BinarySearchTree", mode_name, "удаление", run_number, deletion_time]) rows.append(["BinarySearchTree", mode_name, "вставка", "среднее", sum(insertion_times) / repeats]) rows.append(["BinarySearchTree", mode_name, "поиск", "среднее", sum(finding_times) / repeats]) rows.append(["BinarySearchTree", mode_name, "удаление", "среднее", sum(deletion_times) / repeats]) return rows def save_results(rows, filename="results.csv"): with codecs.open(filename, "a+", "utf-16") as file: writer = csv.writer(file) writer.writerows(rows) def run_shuffled(records_shuffled): rows = measure_bst(records_shuffled, "случайный") save_results(rows) return rows def run_sorted(records_sorted): rows = measure_bst(records_sorted, "отсортированный") save_results(rows) return rows # ---------- Manual tests ---------- def test(): root = None root = bst_insert(root, "Ivan", "111") root = bst_insert(root, "Anna", "222") root = bst_insert(root, "Petr", "333") root = bst_insert(root, "Maria", "444") print(bst_find(root, "Anna")) # 222 print(bst_find(root, "Unknown")) # None root = bst_insert(root, "Anna", "999") print(bst_find(root, "Anna")) # 999 root = bst_delete(root, "Ivan") print(bst_list_all(root)) if __name__ == "__main__": records_shuffled, records_sorted = records() run_shuffled(records_shuffled) run_sorted(records_sorted)