Удаление из BST сложнее вставки: у удаляемого узла могут быть поддеревья, а свойство (левое < узел < правое) нужно сохранить. Всё зависит от числа детей удаляемого узла. О вставке и поиске см. предыдущую тему.

Три случая удаления: лист, один ребёнок, два ребёнка
Три случая удаления: лист, один ребёнок, два ребёнка

Три случая

  1. Лист (детей нет): просто убираем: указатель родителя становится None.
  2. Один ребёнок: убираем узел, а на его место ставим ребёнка (родитель теперь указывает на ребёнка). Поддерево ребёнка свойство не нарушает, потому что оно и раньше было поддеревом удаляемого узла.
  3. Два ребёнка: просто убрать узел нельзя, ведь пришлось бы склеивать два поддерева. Вместо этого заменяем ключ узла ключом его преемника (successor), а затем удаляем преемника. Преемник — наименьший узел правого поддерева. У него нет левого ребёнка, поэтому его удаление относится к случаю 1 или 2.

Выбор преемника сохраняет свойство: он больше всех в левом поддереве и меньше остальных в правом. Симметричный выбор: предшественник (predecessor), наибольший в левом поддереве.

Реализация

python
class Node:
    def __init__(self, key, left=None, right=None):
        self.key = key
        self.left = left
        self.right = right

def insert(node, key):
    if node is None:
        return Node(key)
    if key < node.key:
        node.left = insert(node.left, key)
    elif key > node.key:
        node.right = insert(node.right, key)
    return node

def build(keys):
    root = None
    for k in keys:
        root = insert(root, k)
    return root