Haskell,树的列表列表

时间:2015-09-13 21:09:36

标签: list haskell tree

我有一个树的数据结构:

数据树a = NodeT a(树a)(树a)| EmptyT

我需要创建一个返回列表列表的函数,其中列表的每个元素代表树的一个级别。例如,从中:

          1
         / \
       2     3
      / \   / \
     4   5 6   7     

对此:[[1],[2,3],[4,5,6,7]]

该功能必须具有以下形式:

                     f :: Tree a -> [[a]]

如何使用递归?

由于

2 个答案:

答案 0 :(得分:5)

您递归计算级别并始终逐点合并两个子树中的列表(因此,相同深度的所有切片都会合并在一起)。

f :: Tree a -> [[a]]
f EmptyT = []
f (NodeT a t1 t2) = [a] : merge (f t1) (f t2)

merge :: [[a]] -> [[a]] -> [[a]]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) = (x ++ y) : merge xs ys

如果树完整(从根到列表的所有路径长度相同),那么您可以使用zipWith (++)作为merge

答案 1 :(得分:3)

比接受的解决方案稍微复杂一点,但我认为我的内存消耗方面可能更好(有点晚了,所以请自行检查)。

直觉来自Chris Okasaki "Breadth-First Numbering: Lessons from a Small Exercise in Algorithm Design"的精彩论文。您可以在功能语言中详细了解树的广度优先树遍历。

我添加"列表列表"分裂,可能有更好的方法:

module Main where

data Tree a = NodeT a (Tree a) (Tree a) | EmptyT

--      1
--     / \
--   2     3
--  / \   / \
-- 4   5 6   7     

f :: Tree a -> [[a]]
f t = joinBack (f' [(t, True)])

type UpLevel = Bool

f' :: [(Tree a, UpLevel)] -> [(a, UpLevel)]
f' [] = []
f' ((EmptyT, _) : ts) = f' ts
f' ((NodeT a t1 t2, up) : ts) = (a, up) : f' (ts ++ [(t1, up)] ++ [(t2, False)])

joinBack :: [(a, UpLevel)] -> [[a]]
joinBack = go []
  where
    go acc [] = [reverse acc]
    go acc ((x, False) : xs) = go (x : acc) xs
    go acc ((x, True) : xs) = reverse acc : go [] ((x, False):xs)

main :: IO ()
main = do
  let tree = NodeT 1 (NodeT 2 (NodeT 4 EmptyT EmptyT) (NodeT 5 EmptyT EmptyT))
                     (NodeT 3 (NodeT 6 EmptyT EmptyT) (NodeT 7 EmptyT EmptyT))
             :: Tree Int
  print (tail (f tree))