В BST все значения, спускающиеся с левой стороны узла, меньше (или равны, см. Ниже) самого узла. Точно так же все значения, спускающиеся с правой стороны узла, больше (или равны) значению узла (a) .
Некоторые BST могут разрешить дублирование значений, отсюда и квалификаторы «или равно» выше. Следующий пример может прояснить:
14
/ \
13 22
/ / \
1 16 29
/ \
28 29
Это показывает BST, который допускает дублирование (b) - вы можете видеть, что для поиска значения вы начинаете с корневого узла и идете вниз по левому или правому поддереву в зависимости от того, меньше или больше ваше значение поиска, чем значение узла.
Это можно сделать рекурсивно, например:
def hasVal (node, srchval):
if node == NULL:
return false
if node.val == srchval:
return true
if node.val > srchval:
return hasVal (node.left, srchval)
return hasVal (node.right, srchval)
и вызывая его с помощью:
foundIt = hasVal (rootNode, valToLookFor)
Дубликаты добавляют немного сложности, так как вам может потребоваться продолжить поиск, как только вы найдете свое значение, для других узлов с тем же значением.
(a) Вы можете сортировать их в обратном направлении, если хотите, при условии, что вы настроите способ поиска определенного ключа. BST нужно только поддерживать некоторый отсортированный порядок, независимо от того, возрастающий или убывающий не имеет значения.
(b) Интересно, что если ваш ключ сортировки использует все значение, хранящееся в узле (так что узлы, содержащие один и тот же ключ, не имеют другой дополнительной информации для их различения), может быть повышение производительности от добавления счетчика к каждому узлу, а не позволяя дублировать узлы.
Основное преимущество заключается в том, что добавление или удаление дубликата просто изменяет счетчик, а не вставляет или удаляет новый узел, действие, которое может потребовать повторной балансировки дерева.
Итак, чтобы добавить элемент, вы сначала проверяете, существует ли он. Если да, просто увеличьте счетчик и выйдите. Если нет, вам нужно вставить новый узел со счетчиком, равным единице, а затем выполнить повторную балансировку.
Чтобы удалить элемент, вы находите его, а затем уменьшаете счетчик - только если результирующий счетчик равен нулю, вы затем удаляете фактический узел из дерева и повторно балансируете.
Поиск также выполняется быстрее, учитывая меньшее количество узлов, но это не может иметь большого значения.
Например, следующие два дерева (не считая слева и считая справа) будут эквивалентны (в дереве подсчета i.c
означает c
копии элемента i
):
__14__ ___22.2___
/ \ / \
14 22 7.1 29.1
/ \ / \ / \ / \
1 14 22 29 1.1 14.3 28.1 30.1
\ / \
7 28 30
Удаление листового узла 22
из левого дерева повлечет за собой перебалансировку (поскольку теперь у него разница в высоте 22-29-28-30
равна двум) результирующего поддерева, такого как показано ниже (это один из вариантов, есть и другие, которые также удовлетворяют требованию «разность высоты должна быть равна нулю или единице. "правило):
\ \
22 29
\ / \
29 --> 28 30
/ \ /
28 30 22
Выполнение той же операции в правом дереве представляет собой простую модификацию корневого узла с 22.2
на 22.1
(без необходимости повторной балансировки).