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']
|