我正在尝试编写一个函数,其中记录了导致数据N的所有路径。
任何人都可以给我一些指示,因为我很困惑,我何时记录路径?好像我从头开始,我可能最终会找到能够知道在哪里的路径。 (记录路径为L | R)
任何人都可以给我一些逻辑!
由于
我曾经在一个给定路径的树上工作,但我无法弄清楚
data Tree = N | F Tree Tree deriving Show
data Dir = L | R deriving Show
type Path = [Dir]
所以树可以是F N (F (F N N) (F N (F N N)))
路径为[L,L,L,R]
我已经将函数插入到有N个节点或给定路径的位置。
但我无法理解记录路径的逻辑。
答案 0 :(得分:5)
这不是一个完整的答案,但这是我想到的方式:你可以对树进行深度优先搜索(简单的递归调用),并确保你正在返回正确的在路上的事情。你知道,当你进入子子树时,你会得到一个回路列表,对吗?然后,您只需要考虑如何根据您的子问题得到答案:在这种情况下,将路径扩展到您目前为止所经历的路径。我写了类似
的东西search N = [[]] -- one empty path
search (F x y) = map (L:) (search x) ++
map (R:) (search y)
即,将Left
添加到来自左子问题的解决方案中,将Right
添加到来自右子问题的解决方案中。
答案 1 :(得分:5)
main = print . findAllLeaves $ F N (F (F N N) (F N (F N N)))
data Tree = N | F Tree Tree deriving Show
data Dir = L | R deriving Show
type Path = [Dir]
descend :: Tree -> Dir -> Tree
descend (F l _) L = l
descend (F _ r) R = r
descend _ _ = undefined
findAllLeaves :: Tree -> [Path]
findAllLeaves N = [[]]
findAllLeaves tree = do dir <- [L, R]
map (dir:) $ findAllLeaves (descend tree dir)
结果
[[L],[R,L,L],[R,L,R],[R,R,L],[R,R,R,L],[R,R,R,R]]
我使用list monad同时选择L和R,然后下降两个分支。要爱不确定!
说明:
我希望descend
足够清楚。你给它一棵树和一个方向,它沿那个方向下降树。
findAllLeaves
是有趣的。它是如何工作的?
我们将在一分钟内讨论基本案例findAllLeaves N = [[]]
。
递归案例写在列表monad中,带有do
表示法。第一行很简单:选择L
或R
并将其分配给dir
。 列表monad实际上会选择两者,并为每个结果取得结果并将它们连接在一起。 这是他们理解的关键。这正是你要求的:什么是所有以L
开头的路径,以R
开头的所有路径是什么?将它们放在一起,您就拥有了从当前节点到其后代叶节点的所有路径。
第二行应该从前一段的描述中相当清楚。沿给定方向(descend tree dir
)下降树,找到该点的所有叶子(findAllLeaves
),然后将选择的方向添加到每个子路径(map (dir:)
)。
为什么基本案例[[]]
?那么,考虑一下基本案例之上的情况。例如,findAllLeaves (F N N)
。当我们选择dir = L
时,我们会评估第二行:
map (L:) $ findAllLeaves (descend (F N N) L)
向左下降只给我们N
map (L:) $ findAllLeaves N
然后我们遇到了基本情况:
map (L:) $ [[]]
现在你能看出为什么我们有这种奇怪的基础案例吗?里面有一个空列表的列表?因为我们要将(L:)
映射到它上,换句话说,将L
添加到外部列表中的每个列表中。这导致:
[[L]]
我们在dir = R
时得到了类似的结果。
[[R]]
然后列表monad将这些连接在一起
[[L]] ++ [[R]]
我们最终以
结束[[L], [R]]
如果仍然不清楚,请在评论中告诉我,我会尽力澄清。