153 lines
4.7 KiB
Python
153 lines
4.7 KiB
Python
#реализация справочника на основе бинарного дерева поиска (BST).
|
||
|
||
#создаём узел
|
||
def bst_create_node(name, phone):
|
||
return {
|
||
'name': name,
|
||
'phone': phone,
|
||
'left': None,
|
||
'right': None
|
||
}
|
||
|
||
#Вставляет запись в BST или обновляет.Возвращает корень дерева
|
||
def bst_insert(root, name, phone):
|
||
new_node = bst_create_node(name, phone)
|
||
|
||
if root is None:
|
||
return new_node
|
||
|
||
current = root
|
||
parent = None
|
||
|
||
while current is not None:
|
||
parent = current
|
||
if name < current['name']:
|
||
current = current['left']
|
||
elif name > current['name']:
|
||
current = current['right']
|
||
else:
|
||
current['phone'] = phone
|
||
return root
|
||
|
||
#вставляем новый узел
|
||
if name < parent['name']:
|
||
parent['left'] = new_node
|
||
else:
|
||
parent['right'] = new_node
|
||
|
||
return root
|
||
|
||
#ищет запись в BST по имени. Возвращает телефон или None
|
||
def bst_find(root, name):
|
||
current = root
|
||
|
||
while current is not None:
|
||
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):
|
||
current = node
|
||
while current['left'] is not None:
|
||
current = current['left']
|
||
return current
|
||
|
||
#удаляет запись из BST по имени. Возвращает новый корень дерева
|
||
def bst_delete(root, name):
|
||
if root is None:
|
||
return None
|
||
|
||
parent = None
|
||
current = root
|
||
|
||
while current is not None and current['name'] != name:
|
||
parent = current
|
||
if name < current['name']:
|
||
current = current['left']
|
||
else:
|
||
current = current['right']
|
||
|
||
if current is None:
|
||
return root
|
||
|
||
if current['left'] is None and current['right'] is None:
|
||
if parent is None:
|
||
return None
|
||
elif parent['left'] == current:
|
||
parent['left'] = None
|
||
else:
|
||
parent['right'] = None
|
||
return root
|
||
|
||
if current['left'] is None:
|
||
if parent is None:
|
||
return current['right']
|
||
elif parent['left'] == current:
|
||
parent['left'] = current['right']
|
||
else:
|
||
parent['right'] = current['right']
|
||
return root
|
||
|
||
if current['right'] is None:
|
||
if parent is None:
|
||
return current['left']
|
||
elif parent['left'] == current:
|
||
parent['left'] = current['left']
|
||
else:
|
||
parent['right'] = current['left']
|
||
return root
|
||
|
||
successor_parent = current
|
||
successor = current['right']
|
||
|
||
while successor['left'] is not None:
|
||
successor_parent = successor
|
||
successor = successor['left']
|
||
|
||
current['name'] = successor['name']
|
||
current['phone'] = successor['phone']
|
||
|
||
if successor_parent == current:
|
||
successor_parent['right'] = successor['right']
|
||
else:
|
||
successor_parent['left'] = successor['right']
|
||
|
||
return root
|
||
|
||
#рекурсивно собирает записи дерева по возрастанию имён
|
||
def _bst_in_order_collect(node, records):
|
||
if node is not None:
|
||
_bst_in_order_collect(node['left'], records)
|
||
records.append((node['name'], node['phone']))
|
||
_bst_in_order_collect(node['right'], records)
|
||
|
||
#отсортированный список всех записей
|
||
def bst_list_all(root):
|
||
records = []
|
||
# Для очень глубоких деревьев лучше использовать итеративный обход
|
||
_bst_in_order_iterative(root, records)
|
||
return records
|
||
|
||
#центрированный обход дерева.
|
||
def _bst_in_order_iterative(root, records):
|
||
stack = []
|
||
current = root
|
||
|
||
while current is not None or len(stack) > 0:
|
||
# доходим до самого левого узла
|
||
while current is not None:
|
||
stack.append(current)
|
||
current = current['left']
|
||
|
||
# обрабатываем узел
|
||
current = stack.pop()
|
||
records.append((current['name'], current['phone']))
|
||
|
||
#переходим к правому поддереву
|
||
current = current['right'] |