"""
Двоичное дерево поиска

Узел — словарь:
{'name': 'Имя', 'phone': '123', 'left': None, 'right': None}.
"""

def bst_insert(root: dict|None, name: str, phone: str) -> dict:
    """Итеративно вставляет, возвращает новый корень (если корень меняется)."""
    if root == None:
        return {'name': name, 'phone': phone, 'left': None, 'right': None}
    
    # '674' < '722' == True, lol
    current = root
    while True:
        if current['name'] == name:
            current['phone'] = phone
            return root
        elif name < current['name']:
            if current['left'] == None:
                current['left'] = bst_insert(None, name, phone)
                return root
            else:
                current = current['left']
        else:
            if current['right'] == None:
                current['right'] = bst_insert(None, name, phone)
                return root
            else:
                current = current['right']
    # Увы, это самый лаконичный вариант, который я придумал.


def bst_find(root: dict|None, name: str) -> str|None:
    """Поиск в ширину."""
    node = find_node_to_delete(root, name)
    if node != None:
        return node['phone']

def find_node_to_delete(root: dict|None, name: str) -> dict|None:
    """Поиск в ширину."""
    while root != None:
        if root['name'] == name:
            return root
        elif name < root['name']:
            root = root['left']
        else:
            root = root['right']
    return None

def find_minimal_child(root: dict) -> dict|None:
    while root['left']:
        root = root['left']
    return root

def bst_delete(root: dict, name: str) -> None:
    """Удаляет узел и возвращает новый корень."""
    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:        
        # Случай 1: нет детей или один ребенок
        if root['left'] is None:
            return root['right']
        elif root['right'] is None:
            return root['left']
        
        # Случай 2: два ребенка
        min_node = find_minimal_child(root['right'])
        root['name'] = min_node['name']
        root['phone'] = min_node['phone']
        root['right'] = bst_delete(root['right'], min_node['name'])
    
    return root


def bst_list_all(root: dict) -> list:
    """Центрированный обход.
    Рекурсивно собирает записи в отсортированном порядке."""
    
    if root is None:
        return []
    node_values = {"name": root['name'], "phone": root['phone']}
    return bst_list_all(root['left']) + [node_values] + bst_list_all(root['right'])