在Haskell树中查找最接近整数参数的键
在命令式语言中,如何在二叉树中找到最接近的上下键有很多解决方案,但在Haskell这样的纯函数式风格中,缺少相同的问题。我很想知道,在遇到两个最近的键之前,如何绕过一棵二叉树。到目前为止,我已经完成了一个函数和一些模式匹配:在Haskell树中查找最接近整数参数的键,haskell,functional-programming,binary-search-tree,Haskell,Functional Programming,Binary Search Tree,在命令式语言中,如何在二叉树中找到最接近的上下键有很多解决方案,但在Haskell这样的纯函数式风格中,缺少相同的问题。我很想知道,在遇到两个最近的键之前,如何绕过一棵二叉树。到目前为止,我已经完成了一个函数和一些模式匹配: data TreeMap v = Leaf | Node { pair::(Integer, v), l::TreeMap v, r::TreeMap v} deriving (Show, Read, Eq, Ord) closestLess :: Integer -&g
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
data TreeMap v=Leaf | Node{pair::(整数,v),l::TreeMap v,r::TreeMap v}派生(显示,读取,Eq,Ord)
无闭::整数->树映射v->(整数,v)
closestLess i Leaf=错误“树不包含任何元素”
无闭i(节点对树\u r树\u l)
|i
我使用这个函数来获取一个较低的键,但最接近整数参数。在我看来,除了实现“精确”这样的辅助功能外,没有别的必要,尽管我不清楚它到底需要什么定义。我的建议是将整数值节点放入“精确”的右子树中,也可以找到离目标最近的任何键。因此,我会有一些提示或假设,如何使它为较低和较高的关键以及 以下是我的做法:
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
关于此操作与您的尝试之间的差异,请注意以下几点:
- 您为
构造函数使用了记录语法。在sum类型上使用记录语法是一种糟糕的形式,因为这样函数将是部分函数(例如,节点
将位于底部)。因为你实际上没有使用这些,而且它们也不是必需的,所以我把它们拿走了pairleaf
- 您将键和值包装在一个元组中,没有明显的原因。我把它们分开,直接放在打字机上
- 您的
函数的返回类型为closestLess
,尽管它不能始终返回该类型的内容。我将它改为(Integer,v)
,这样它就可以返回Maybe(Integer,v)
,而不必使用Nothing
。(旁注:您的错误消息在技术上是错误的。如果在搜索值小于所有节点的情况下调用error
,则即使树中有元素,也会失败。)closestLess
- 您的代码在节点的左分支和右分支方面不一致。在我的代码中,左分支始终是数据构造函数中位于左侧的分支
- 您在单独的保护中使用了
和i
。通过对i==fst对
的输出进行大小写匹配,您只需执行一次而不是两次比较compare
- 您需要一个
功能,这是正确的,但是精确的
中的许多逻辑实际上需要在其中无触点
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
您还可以让它变得更懒惰(只要找到一个候选者,就产生外部的
,代价是变得更复杂:
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
导入Data.Functor.Identity
数据树映射v=叶|节点整数v(树映射v)(树映射v)派生(显示、读取、等式、Ord)
无闭::整数->树映射v->可能(整数,v)
无闭合i=精确无
哪里
精确::应用程序t=>t(整数,v)->树映射v->t(整数,v)
精确的closestSoFar叶=closestSoFar
精确闭合时间(节点k v l r)=案例i`compare`k of
LT->精确关闭至左侧
等式->纯(k,v)
GT->pure。runIdentity$precise(Identity(k,v))r
有关它的更多详细信息,请参阅。我不知道您希望precise
函数做什么。此外,避免在纯函数中抛出错误
s,而是为结果找到更好的表示形式(如使用Maybe
)您是否可以发布一个有效的最接近的下键的命令式版本
,以便我们能够确切地了解您希望haskell版本做什么?按照@Bergi的请求,我添加了类型定义。对不起mistake@Bergi我需要解决的问题是,正如本教程中C++程序员所说的,我认为你可以很好地遵循他们的算法——除了那些怪异的、可变的<代码> MimoDIFI和 MimiDeopyKyth参数,更糟糕的是,它还有一些无值值,如MAX\u INTEGER
和-1
。编写一个函数Integer->TreeMap v->Maybe(Integer,v)->Maybe(Integer,v)
,其中包含参数searchValue
,tree
,以及closestSoFar
。它工作得非常好,谢谢。事实上,这是对这个案例解决方案的一个非常出色的解释——作为函数式编程的新手,我非常感谢您对所有这些的评论和结论。