有很多解决方案,如何以命令式语言在二叉树中查找最接近的上下键,但是在像Haskell这样的纯函数样式中进行操作时,缺少相同的问题。我很好奇要学习在遇到两个最接近的键之前如何绕过二叉树。到目前为止,有一个功能和一些模式匹配:
data TreeMap v = Leaf | Node { pair::(Integer, v), l::TreeMap v, r::TreeMap v} deriving (Show, Read, Eq, Ord)
closestLess :: Integer -> TreeMap v -> (Integer, v)
closestLess i Leaf = error "Tree doesn't include any element"
closestLess i (Node pair tree_r tree_l)
| i < fst pair = closestLess i tree_l
| i == fst pair = closestLess i tree_r
| otherwise = precise i pair tree_r
我使用此函数来获取一个较低的键,但最接近Integer参数。我认为,除了实现“精确”之类的辅助功能外,没有什么必要,尽管我对它确切需要什么定义感到困惑。我的建议是将整数值节点置于“精确”右子树中,以找到最接近目标的任何键。因此,我将有一些技巧或假设,也适用于上下键。
答案 0 :(得分:0)
这就是我要做的:
data TreeMap v = Leaf | Node Integer v (TreeMap v) (TreeMap v) deriving (Show, Read, Eq, Ord)
closestLess :: Integer -> TreeMap v -> Maybe (Integer, v)
closestLess i = precise Nothing where
precise :: Maybe (Integer, v) -> TreeMap v -> Maybe (Integer, v)
precise closestSoFar Leaf = closestSoFar
precise closestSoFar (Node k v l r) = case i `compare` k of
LT -> precise closestSoFar l
EQ -> Just (k, v)
GT -> precise (Just (k, v)) r
有关此尝试与您尝试之间的区别的一些注意事项:
Node
构造函数。在总和类型上使用记录语法是一种不好的形式,因为函数将是部分的(例如,pair Leaf
将是底部的)。由于您实际上并没有使用它们,因此也没有必要,因此我将其删除。closestLess
函数的返回类型为(Integer, v)
,即使它不能总是返回该类型的内容。我将其更改为Maybe (Integer, v)
,以便它可以返回Nothing
,而不必使用error
。 (附带说明:您的错误消息在技术上是错误的。如果您在搜索值小于所有节点的地方调用closestLess
,即使树中确实包含元素,它也会失败。)i < fst pair
和i == fst pair
。通过对compare
的输出进行大小写匹配,您只需进行一次比较即可,而无需进行两次比较。precise
函数,才走上了正确的轨道,但是实际上closestLess
中需要包含的许多逻辑都需要包含在其中。这是一个快速测试案例,使用您链接的站点上的示例:
Prelude> tree = Node 9 () (Node 4 () (Node 3 () Leaf Leaf) (Node 6 () (Node 5 () Leaf Leaf) (Node 7 () Leaf Leaf))) (Node 17 () Leaf (Node 22 () (Node 20 () Leaf Leaf) Leaf))
Prelude> closestLess 4 tree
Just (4,())
Prelude> closestLess 18 tree
Just (17,())
Prelude> closestLess 12 tree
Just (9,())
Prelude> closestLess 2 tree
Nothing
您还可以使其变得更懒惰(一旦找到一个候选者,立即产生外部Just
),但会变得更加复杂:
import Data.Functor.Identity data TreeMap v = Leaf | Node Integer v (TreeMap v) (TreeMap v) deriving (Show, Read, Eq, Ord) closestLess :: Integer -> TreeMap v -> Maybe (Integer, v) closestLess i = precise Nothing where precise :: Applicative t => t (Integer, v) -> TreeMap v -> t (Integer, v) precise closestSoFar Leaf = closestSoFar precise closestSoFar (Node k v l r) = case i `compare` k of LT -> precise closestSoFar l EQ -> pure (k, v) GT -> pure . runIdentity $ precise (Identity (k, v)) r
有关其更多详细信息,请参见my question about this。