使用二叉树中的数据记录所有路径

时间:2011-05-31 18:13:34

标签: haskell

我正在尝试编写一个函数,其中记录了导致数据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个节点或给定路径的位置。

但我无法理解记录路径的逻辑。

2 个答案:

答案 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表示法。第一行很简单:选择LR并将其分配给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]]

如果仍然不清楚,请在评论中告诉我,我会尽力澄清。