Удаление из BST сложнее вставки: у удаляемого узла могут быть поддеревья, а свойство (левое < узел < правое) нужно сохранить. Всё зависит от числа детей удаляемого узла. О вставке и поиске см. предыдущую тему.
Три случая
- Лист (детей нет): просто убираем: указатель родителя становится
None. - Один ребёнок: убираем узел, а на его место ставим ребёнка (родитель теперь указывает на ребёнка). Поддерево ребёнка свойство не нарушает, потому что оно и раньше было поддеревом удаляемого узла.
- Два ребёнка: просто убрать узел нельзя, ведь пришлось бы склеивать два поддерева. Вместо этого заменяем ключ узла ключом его преемника (successor), а затем удаляем преемника. Преемник — наименьший узел правого поддерева. У него нет левого ребёнка, поэтому его удаление относится к случаю 1 или 2.
Выбор преемника сохраняет свойство: он больше всех в левом поддереве и меньше остальных в правом. Симметричный выбор: предшественник (predecessor), наибольший в левом поддереве.
Реализация
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