type BSTree a = BinaryTree a
data BinaryTree a = Null | Node (BinaryTree a) a (BinaryTree a)
deriving Show
flattenTree :: BinaryTree a -> [a]
flattenTree tree = case tree of
Null -> []
Node left val right -> (flattenTree left) ++ [val] ++ (flattenTree right)
isBSTree :: (Ord a) => BinaryTree a -> Bool
isBSTree btree = case btree of
Null -> False
tree -> (flattenTree tree) == sort (flattenTree tree)
Я хочу написать функцию для определения, является ли данное дерево бинарным деревом поиска. Мой метод состоит в том, чтобы сгруппировать все значения в списке и импортировать их, Data.List
а затем отсортировать список, чтобы определить, равны ли они, но это немного сложно. Можем ли мы сделать это без импорта другого модуля?
flattenTree
первым. Вы можете вернутьсяFalse
рано, если узел нарушает свойство поиска, не обходя все поддерево, укорененное в этом узле.sort
, а не сflattenTree
, который достаточно ленив.Ответы:
Вот способ сделать это без сплющивания дерева.
Из определения здесь
Можно видеть, что обход дерева слева направо, игнорирование
Node
и скобки дают чередующуюся последовательностьNull
s иa
s. То есть между каждыми двумя значениями естьNull
.Мой план состоит в том, чтобы проверить, что каждое поддерево удовлетворяет подходящим требованиям : мы можем уточнить требования к каждому
Node
, помня, с какими значениями мы находимся, а затем протестировать их на каждомNull
. ПосколькуNull
между значениями в каждом порядке есть пара значений, мы проверим, что все в порядке (слева направо) пары не убывают.Что такое требование? Это свободная нижняя и верхняя граница значений в дереве. Чтобы выразить требования, включая те, которые находятся слева и справа, мы можем расширить любой порядок с помощью
Bot
тома иTop
элементов следующим образом:Теперь давайте проверим, что данное дерево удовлетворяет требованиям как по порядку, так и между заданными границами.
Двоичное дерево поиска - это дерево, которое находится в порядке и между
Bot
иTop
.Вычисление фактических экстремальных значений в каждом поддереве, всплытие их наружу, дает вам больше информации, чем вам нужно, и очень сложно в тех случаях, когда левое или правое поддерево пусто. Поддерживать и проверять требования , толкая их внутрь, довольно равномерно.
источник
Вот подсказка: сделайте вспомогательную функцию
где
BSTResult a
определяется какВы должны быть в состоянии продолжить рекурсивно, используя результаты на поддеревьях для управления вычислениями, в частности, минимума и максимума.
Например, если у вас есть
tree = Node left 20 right
, сisBSTree' left = NonEmptyBST 1 14
иisBSTree' right = NonEmptyBST 21 45
, тоisBSTree' tree
должно бытьNonEmptyBST 1 45
.В том же случае, за исключением
tree = Node left 24 right
, мы должны вместо этогоisBSTree' tree = NotBST
.Преобразование результата в
Bool
затем тривиально.источник
BSTResult a
и сложите его. :) (или даже если это не законный моноид ....)Да , вам не нужно сортировать список. Вы можете проверить, является ли каждый элемент меньше или равен следующему элементу. Это более эффективно, так как мы можем сделать это в O (n) , тогда как оценка отсортированного списка полностью занимает O (n log n) .
Таким образом, мы можем проверить это с:
Таким образом, мы можем проверить, является ли двоичное дерево бинарным деревом поиска с помощью:
Я думаю, что можно утверждать, что оно
Null
само является бинарным деревом поиска, поскольку оно пустое. Таким образом, это означает, что для каждого узла (нет узлов) элементы в левом поддереве меньше или равны значению в узле, а все элементы в правом поддереве больше или равны значению в узле ,источник
Мы можем перейти слева направо по дереву следующим образом:
Вдохновленный Джоном Маккарти
gopher
.Явный выпадающий список можно устранить с помощью продолжения,
Достаточно сохранить только один, самый большой на данный момент элемент.
источник