我正在编写一个函数来检查树是否是BST。我所尝试的只是按顺序遍历列表打印树,然后检查列表是否在增加。但是我遇到了这个错误:
Couldn't match expected type `a' against inferred type `[t]'
`a' is a rigid type variable bound by
the type signature for `checkList' at BST.hs:24:18
In the pattern: x : y : xs
In the pattern: [x : y : xs]
In the definition of `checkList':
checkList [x : y : xs] = x <= y && checkList (y : xs)
这是我到目前为止(只有一个checkList函数)。
checkList :: (Ord a) => [a] -> Bool
checkList [] = True
checkList [x] = True
checkList [x:y:xs] = x <= y && checkList (y:xs)
答案 0 :(得分:7)
你想:
checkList :: (Ord a) => [a] -> Bool
checkList [] = True
checkList [x] = True
checkList (x:y:xs) = x <= y && checkList (y:xs)
当您尝试在最终模式中使用[ ]
时,您说“匹配包含x:y:xs
(也是列表!)的列表作为其唯一元素”。哪个与[a]
类型不匹配。
答案 1 :(得分:2)
使用foldl'
checkList :: Ord a => [a] -> Bool
checkList xs = fst $ foldl' (\(b,x1) x2 -> (b && x1 <= x2,x2)) (True,head xs) xs
注意:由于懒惰的评估,使用head xs
就可以了。
答案 2 :(得分:2)
通常的做法是让你的树可折叠:
data BST a = Node (BST a) a (BST a) | Leaf
-- Use `deriving Foldable` or this instance
instance Foldable BST where
foldMap _ Leaf = mempty
foldMap f (Node l v r) =
foldMap f l <> (f v <> foldMap f r)
然后你可以跳过转换到这样的列表。这类似于bmk的答案,但避免使用head
。
-- Is this increasing? If so, what is the maximum?
data Result a = Empty | NotInc | Inc a
finalInc :: Result a -> Bool
finalInc NotInc = False
finalInc _ = True
increasing :: (Foldable f, Ord a) => f a -> Bool
increasing = finalInc . foldl' go Empty where
go Empty y = Inc y
go NotInc _ = NotInc
go (Inc x) y
| x <= y = Inc y
| otherwise = NotInc
此检查的属性比传统的二进制搜索树属性弱,并且弱于弱化该属性的常用方法。特别是,您通常希望至少确保每个子树的根严格大于其左子树的所有元素,或者每个子树的根严格> 少于其右子树的所有元素。这些弱属性无法以Foldable
实例或转换为列表的形式表示;他们必须直接检查。但是,您只需使用<=
替换<
,即可使用这些技术验证经典的BST属性。
包括这个在内的所有答案都有一些不幸的属性:给定一个非常重的树(例如Node (Node (...) 2 Leaf) 1 Leaf
),他们将使用O(n)
额外的空间来验证搜索树属性。有没有办法写这个,所以它不会有任何这样的坏案例?不幸的是,答案似乎是否定的。因此可以说明经典的BST属性:
每个节点必须大于其左子树的所有元素,并且少于其右子树的所有元素。
问题在于&#34;和&#34;。如果我们决定首先检查左子树,我们必须记住以便在之后检查正确的子树,反之亦然。
因此,唯一方式使验证更有效率是确保树是平衡的。