将所有路径和数据记录在二叉树中

问题描述

| 我正在尝试编写一个函数,在其中记录导致数据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,R]
我已经制作了一些函数来插入有N个节点或给定路径的位置。 但是我无法理解记录路径的逻辑。     

解决方法

        
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],R,R]]
我使用列表monad来“同时”选择L和R,然后下降两个分支。要爱不确定性! 说明: 我希望ѭ5足够清楚。您给它一棵树和一个方向,然后它沿该方向下降。
findAllLeaves
是有趣的。它是如何工作的? 我们将在稍后讨论基本情况
findAllLeaves N = [[]]
。 递归的情况用8表示法写在列表monad中。第一行很简单:选择
L
R
并将其分配给
dir
。列表monad实际上会选择两者,然后取每个结果并将它们连接在一起。这是他们理解的关键。这正是您要的:以
L
开头的所有路径是什么,以
R
开头的所有路径是什么?将它们放在一起,您便拥有了从当前节点到其后代叶子节点的所有路径。 从上一段的描述中,第二行应该相当清楚。沿给定方向(
descend tree dir
)下降树,找到该点的所有叶子(ѭ6all),然后将选择的方向置于每个子路径(
map (dir:)
)的前面。 那为什么要case17ѭ呢?好吧,考虑一下基本案例之上的案例。因此,例如,
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]]
如果尚不清楚,请在评论中让我知道,我将尽力澄清。     ,        这不是一个完整的答案,但这是我考虑的方式:您可以对树进行深度优先搜索(简单的递归调用),并确保您返回的是正确的东西在上升。您知道,当您递归到子子树时,您将获得返回的路径列表,对吗?然后,您只需要考虑给定子问题的答案即可:在这种情况下,将路径扩展到您迄今为止所走过的路径。我会写类似
search N = [[]] -- one empty path
search (F x y) = map (L:) (search x) ++
    map (R:) (search y)
也就是说,将
Left
放在来自左子问题的解中,并将
Right
放在来自右子问题的解中。