Haskell-查找节点值的路径
这个问题的问题是: 树保存类型a的数据。函数findpath给定函数f、一些数据x和树t,将t中的路径列表(可能为空)返回到形式为Node d的节点,其中fd等于x 此问题中使用的数据类型的声明结构:Haskell-查找节点值的路径,haskell,tree,nodes,Haskell,Tree,Nodes,这个问题的问题是: 树保存类型a的数据。函数findpath给定函数f、一些数据x和树t,将t中的路径列表(可能为空)返回到形式为Node d的节点,其中fd等于x 此问题中使用的数据类型的声明结构: data Btree a = ND | Data a | Branch (Btree a) (Btree a) deriving (Show,Eq) data Dir = L | R deriving (Show,Eq) type Path = [Di
data Btree a = ND | Data a | Branch (Btree a) (Btree a)
deriving (Show,Eq)
data Dir = L | R
deriving (Show,Eq)
type Path = [Dir]
我尝试解决此函数:
findpath :: Eq b => (a -> b) -> b -> Btree a -> [Path]
findpath f x (Data d) = [[]]
findpath f x ND = [[]]
findpath f x (Branch (Data d) right) = [[L]] ++ (findpath f x right)
findpath f x (Branch left (Data d)) = [[R]] ++ (findpath f x left)
1. findpath (2*) 3 tree2
2. findpath (2*) 2 tree2
3. findpath (2*) 3 tree1
用于测试的数据:
tree1 = Branch ND ND
tree2 = Branch ND (Data 3)
tree3 = Branch tree1 tree2
用于测试函数的函数调用:
findpath :: Eq b => (a -> b) -> b -> Btree a -> [Path]
findpath f x (Data d) = [[]]
findpath f x ND = [[]]
findpath f x (Branch (Data d) right) = [[L]] ++ (findpath f x right)
findpath f x (Branch left (Data d)) = [[R]] ++ (findpath f x left)
1. findpath (2*) 3 tree2
2. findpath (2*) 2 tree2
3. findpath (2*) 3 tree1
它给出的输出是:
1. [[R],[]]
2. [[R],[]] - incorrect
3. Throws exception
如果您对findpath函数有任何帮助,我们将不胜感激 让我们一次处理一个案例,完全使用
Btree
的数据定义中的案例。就是因为
data Btree a = ND | Data a | Branch (Btree a) (Btree a)
那么我们将完全考虑以下形状的树木,而没有其他形状:
ND
数据d
分支机构l/r
findpath f x ND = {- TODO -}
回想一下规格:
函数findpath给定函数f、一些数据x和树t,将t中的路径列表(可能为空)返回到表单数据d的节点,其中fd等于x
(我假设您在写“节点d”的地方,您的意思是“数据d”,以符合您对树的定义,并将“列表”更改为“列表”。)
在当前情况下,我们有f
和x
,如前所述,以及t=ND
。将这些内容替换为我们应该返回的内容,我们得到:
ND中指向表单数据d节点的路径列表,其中
由于ND
不包含任何形式为Data d
的节点,因此不存在此类路径。因此:
findpath f x ND = []
findpath f x (Data d) = if f d == x
then [[]]
else []
下一个案例:
findpath f x (Data d) = {- TODO -}
现在我们有了t=Data d
。再次修改规范,我们必须返回
Data d
中到表单Data d节点的路径列表,其中fd等于x
好的,那么我们必须检查fd
是否等于x
,嘿
findpath f x (Data d) = if f d == x
then {- TODO -}
else {- TODO -}
如果fd==x
,那么表单数据d的节点正好有一条路径,其中fd等于x——即空路径。如果不是fd==x
,那么就没有这样的路径。因此:
findpath f x ND = []
findpath f x (Data d) = if f d == x
then [[]]
else []
最后一种情况是:
findpath f x (Branch l r) = {- TODO -}
再次修改规范,现在使用t=Branch l r
,我们必须返回
分支lr
中指向表单数据d节点的路径列表,其中fd等于x
现在你可能觉得有点卡住了。毕竟,l
和r
是如此普遍,以至于很难知道是否有到表单数据d节点的路径,对吗?那么,您如何才能发现是否有一条进入分支l r的路径最终在数据d节点处结束?当然,如果只有一种方法可以找到这两个子问题的答案,也许我们可以扩大这些路径,嘿
幸运的是,我们有一个函数可以回答这个子问题:findpath
本身。那么,让我们回答这些子问题,然后思考该怎么做
findpath f x (Branch l r) = {- TODO -} where
pathsInL = findpath f x l
pathsInR = findpath f x r
好的,我们在树l
中有一些路径,它们指向Data d
形式的节点,其中fx
等于d
(分别是树r
中的一些路径)。我们如何将这些路径转换为树分支lr
中的路径?简单:通过将L
(分别为R
)预加到每个路径。然后我们可以将这两个路径集合组合在一起
此时,我将停止提供代码:我认为您缺少的关键洞察应该已经在上面提供的递归框架中了。但是,我将建议一些功能,您可能会发现这些功能在充实骨架的最后一部分时很有用:
(:)
可用于将新的目录
预先添加到路径
map
可用于将修改单个路径的函数升级为修改整个路径列表的函数
(++)
可用于连接两个路径列表
s,生成一个包含其两个参数中每个参数的所有元素的列表试一试,让我们知道你下一步会被困在哪里 在
findpath fx(数据d)
的情况下,您不需要检查fd==x
?否则,f
和x
将永远不会使用!这不是唯一的问题,但你可以开始解决这个问题。好吧,你首先要解决的问题是,你的路径列表永远不能为空,因为你的函数实际上都不会返回空列表。因此,您立即违反了自己的规范。你也从来没有真正检查过你的x
是否等于d
,所以你得到的路径当然是错误的。这个问题比你以前的草稿有了很大的改进,干得好!作为提示,请尝试处理一般情况findpath f x(Branch left right)
,其中left
和right
可以是任意子树。现在,您需要其中一个是数据…
,但情况并非总是如此。您需要使用递归并小心地在正确的位置添加一些L
或R
。可能一些列表的串联会很有用。当你是一个初学者的时候,这不是一件小事,所以如果你一开始看不到解决方案,不要惊慌。顺便说一句,我认为这个函数的规格不是很好。我更喜欢类型签名findpath::(a->Bool)->b树a->[Path]
,并将规范中的“其中fd等于x”替换为“其中fd为真”。这样,如果调用方愿意,可以使用完全相等以外的其他谓词。当然,findpath的两种形式可以通过findpathDA fx=findpathDW((x==).f)
和findpathDW p=findpathDA p True
很容易地相互转换,但仍然如此。@DrAnonymous哈哈,哇!在datad
案例中,我没有将规范正确地翻译成代码。你能发现这个错误吗?=)那么这个bug就在