Find whether a tree is a binary search tree in Haskell

Jay*_*yyy 9 tree binary-tree haskell predicate binary-search-tree

  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)
Run Code Online (Sandbox Code Playgroud)

我想做的是编写一个函数来确定给定的树是否是二叉搜索树,我的方法是将所有值分组到一个列表中并导入Data.List,然后对列表进行排序以查找它们是否相等,但是有点复杂。我们可以不导入其他模块就能做到吗?

pig*_*ker 11

这是一种无需展平树木的方法。

根据定义,

data BinaryTree a = Null | Node (BinaryTree a) a (BinaryTree a)
     deriving Show
Run Code Online (Sandbox Code Playgroud)

可以看到,从左到右遍历树,忽略Node并加上括号,会给您Nulls和as 的交替序列。也就是说,每两个值之间有一个Null

我的计划是检查每个子树是否满足合适的需求:我们可以在每个子树上完善需求Node,记住我们之间的值,然后在每个子树上进行测试Null。由于Null在每个有序的值对之间都有一个,因此我们将测试所有有序的(从左至右)对都不会减少。

有什么要求?它是树中值的宽松上下限。为了表达需求,包括最左边和最右边的需求,我们可以使用Bottom和Topelements 扩展任何顺序,如下所示:

data TopBot a = Bot | Val a | Top deriving (Show, Eq, Ord)
Run Code Online (Sandbox Code Playgroud)

现在让我们检查给定的树是否满足顺序和在给定范围之间的要求。

ordBetween :: Ord a => TopBot a -> TopBot a -> BinaryTree a -> Bool
  -- tighten the demanded bounds, left and right of any Node
ordBetween lo hi (Node l x r) = ordBetween lo (Val x) l && ordBetween (Val x) hi r
  -- check that the demanded bounds are in order when we reach Null
ordBetween lo hi Null         = lo <= hi
Run Code Online (Sandbox Code Playgroud)

二叉搜索树是树是为了和之间BotTop

isBSTree :: Ord a => BinaryTree a -> Bool
isBSTree = ordBetween Bot Top
Run Code Online (Sandbox Code Playgroud)

计算每个子树中的实际极值,使其向外冒泡,会为您提供比您所需更多的信息,并且在左右子树为空的边缘情况下比较麻烦。维护和检查需求,将需求向内推,则更加统一。


chi*_*chi 6

这是一个提示:做一个辅助功能

isBSTree' :: (Ord a) => BinaryTree a -> BSTResult a
Run Code Online (Sandbox Code Playgroud)

在哪里BSTResult a定义为

data BSTResult a
   = NotBST             -- not a BST
   | EmptyBST           -- empty tree (hence a BST)
   | NonEmptyBST a a    -- nonempty BST with provided minimum and maximum
Run Code Online (Sandbox Code Playgroud)

您应该能够递归进行,利用子树上的结果来驱动计算,尤其是最小和最大。

例如,如果您有tree = Node left 20 right,和isBSTree' left = NonEmptyBST 1 14isBSTree' right = NonEmptyBST 21 45isBSTree' tree则应为NonEmptyBST 1 45

在相同的情况下tree = Node left 24 right,我们应该有isBSTree' tree = NotBST

Bool然后将结果转换为微不足道的。


Wil*_*sem 3

是的,您不需要对列表进行排序。您可以检查每个元素是否小于或等于下一个元素。这是更有效的,因为我们可以在O(n)中完成此操作,而评估排序列表完全需要O(n log n)

因此我们可以通过以下方式检查:

ordered :: Ord a => [a] -> Bool
ordered [] = True
ordered xa@(_:xs) = and (zipWith (<=) xa xs)
Run Code Online (Sandbox Code Playgroud)

所以我们可以检查二叉树是否是二叉搜索树:

isBSTree :: Ord a => BinaryTree a -> Bool
isBSTree = ordered . flattenTree
Run Code Online (Sandbox Code Playgroud)

我认为人们可以声称Null它本身是一棵二叉搜索树,因为它是一棵空树。这意味着对于每个节点(没有节点),左子树中的元素都小于或等于该节点中的值,并且右子树中的元素都大于或等于该节点中的值。