Haskell 追踪一棵树?

Haskell 追踪一棵树?,haskell,Haskell,我有这样一个树的类型: data Tree a = EmptyTree | Tree a [Tree a] deriving (Show, Ord, Eq) freeTree :: Tree Integer freeTree = Tree 2 [Tree 5 [], Tree 6 [Tree 8 [], Tree 9 []], Tree 7 []] main = print freeTree 我想做的是写一个函数,可以这样使用: trace freeTree 这棵树上的跟踪将返回:

我有这样一个树的类型:

data Tree a = EmptyTree | Tree a [Tree a] deriving (Show, Ord, Eq)

freeTree :: Tree Integer  
freeTree =  Tree 2 [Tree 5 [], Tree 6 [Tree 8 [], Tree 9 []], Tree 7 []]

main = print freeTree
我想做的是写一个函数,可以这样使用:

trace freeTree
这棵树上的跟踪将返回:
[2],[2,5],[2,6],[2,7],[2,6,8],[2,6,9]

基本上它的作用是:

保留“堆栈”上已经存在的节点列表(每个深度的根节点使我们到达这里)。每次到达一个新节点时,将一个列表添加到结果列表中,该列表是堆栈节点+当前_节点的列表

有人能就如何做到这一点提供一些建议吗


谢谢

基本上,您希望在对
跟踪的递归调用中保持状态。因此,考虑这样的函数签名:

-- First argument is the tree to trace
-- Second argument is the accumulated route
trace :: Tree a -> [a] -> [[a]]

使用此结构,您可以有效地在此树上执行深度优先搜索

我们可以认为我们有一个节点,其中每个节点标记一个有效单词,然后工作就是登记单词:

trace :: Tree a -> [[a]]
trace (Tree a ts) = [a] : map (a:) (trace =<< ts)
trace Empty       = []

tree1 = Tree 1 [Tree 2 [ Tree 3 [ Tree 4 [Tree 5 [] ]]]]
tree2 = Tree 2 [Tree 5 [], Tree 6 [Tree 8 [], Tree 9 []], Tree 7 []]

-- trace tree1 = [[1],[1,2],[1,2,3],[1,2,3,4],[1,2,3,4,5]]
-- trace tree2 = [[2],[2,5],[2,6],[2,6,8],[2,6,9],[2,7]]
trace::树a->[[a]]
跟踪(树a ts)=[a]:映射(a:)(跟踪=a第一个(不是真正有效的实现):

该算法使用两个
级别a
,即当前级别和下一级别。您总是首先在当前级别上迭代,并且对于当前级别中的每个项目,您将该级别的子项添加到下一级别,直到当前级别耗尽。此方法唯一的问题是
+
操作非常复杂昂贵,特别是因为它们应用于左关联而非右关联。通过使用更紧凑的元组列表表示,还可以提高内存效率

例如,您可以通过使用FIFO队列来提高效率(假设所有队列的接口至少相同,因此如果您喜欢另一个队列,您可以交换位置)

在这种情况下,代码应为:

type Level a = [([a],Tree a)]
type LevelFiF a = FIFO ([a],Tree a)

trace' :: Level a -> LevelFiF a -> [[a]]
trace' [] ln | isEmpty ln = []
             | otherwise = trace' (toList ln) empty
trace' ((h,Tree t c):ts) ln = ht : trace' ts (foldl (flip enqueue) ln el)
    where ht = h++[t]
          el = map (\x -> (ht,x)) c
trace' (_:ts) ln = ht : trace' ts ln

您也可以使用Haskell的一元队列来提高效率。

对不起,我不懂这种语言。这似乎是一个数据结构问题。这是一个二叉树吗?但似乎是一个树遍历,我假设2是一个可能的根。您的意思是堆栈,因为每个父节点都从根开始?所以2->6->8将是一个显示为[2,6,8]的分支,对吗?这看起来像是对树的广度优先搜索。@chi确实是这样,但棘手的是要追溯路径。@KyleCalica St确切地说,这是一棵树,不一定是二进制为什么第二个参数
[a]
?第二个参数是从树的根节点到当前节点的路径。此跟踪函数只处理一个节点,并递归处理其子节点。
trace :: Tree a -> [[a]]
trace t = trace' [([],t)] []

type Level a = [([a],Tree a)]

trace' :: Level a -> Level a -> [[a]]
trace' [] [] = []                                         -- current and next level empty? We're done!
trace' [] l = trace' l []                                 -- current level exhausted? Next level becomes current level and we construct a new level
trace' ((_,EmptyTree):ts) lu = trace' ts lu               -- currently an EmptyTree? Skip it
trace' ((h,Tree t c):ts) lu = ht : trace' ts (lu++el)     -- currently a tree? Enumerate and add childs
    where ht = h++[t]
          el = map (\x -> (ht,x)) c
type Level a = [([a],Tree a)]
type LevelFiF a = FIFO ([a],Tree a)

trace' :: Level a -> LevelFiF a -> [[a]]
trace' [] ln | isEmpty ln = []
             | otherwise = trace' (toList ln) empty
trace' ((h,Tree t c):ts) ln = ht : trace' ts (foldl (flip enqueue) ln el)
    where ht = h++[t]
          el = map (\x -> (ht,x)) c
trace' (_:ts) ln = ht : trace' ts ln