【问题标题】:Haskell: build a tree from a listHaskell:从列表中构建一棵树
【发布时间】:2014-02-07 20:25:15
【问题描述】:

考虑以下类型:

data LTree a = Leaf a | Fork (LTree a) (LTree a)

现在考虑以下列出树的叶子及其深度的函数

tolistdepth :: LTree a -> [(a,Int)]
tolistdepth (Leaf x) = [(x,0)]
tolistdepth (Fork e d) = map (\(x,n) -> (x,n+1)) (tolistdepth e ++ tolistdepth d)

我需要帮助定义以下函数

build :: [(a, Int)] -> LTree a

计算第一个函数的逆函数,以便

build (tolistdepth a) = a

我什至不知道从哪里开始:)


我已经设法做到了以下几点:

build :: [(a, Int)] -> LTree a
build xs = let ys= map (\(x, n) -> (Leaf x, n)) xs
           in SOMETHING iterateUntil SOMETHING (buildAssist ys)

buildAssist :: [(LTree a, Int)] -> [(LTree a, Int)]
buildAssist [] = []
buildAssist [x] = [x]
buildAssist (x@(t1, n1):y@(t2, n2):xs) = if n1 == n2 then ((Fork t1 t2), n1 - 1):buildAssist xs
                                                     else x:(buildAssist (y:xs))

这样,我想我已经处理了何时分叉。 现在,如何在我的原始函数中使用 buildAssist(如果 buildAssist 当然有用的话)?


我相信我已经弄明白了。

如果可行,请告诉我:

build :: [(a,Int)] -> LTree a
build l = fst (buildaccum 0 l)

buildaccum :: Int -> [(a,Int)] -> (LTree a, [(a,Int)])
buildaccum n l@((a,b):t) |n==b = (Leaf a,t)
                         |n<b = (Fork e d, l2)
     where (e,l1) = buildaccum (n+1) l
           (d,l2) = buildaccum (n+2) l1

【问题讨论】:

  • 你对构建的论点有什么假设?并非所有可能的输入都可以生成树。
  • @ChrisTaylor 假设输入可以做成一棵树。谢谢指出
  • 我认为你可以使用你的buildAssist,如果你继续调用它直到你得到一个元素。
  • @user5402 你能详细说明我该怎么做吗?
  • 我更新了我的答案。一旦你的方法奏效,我会发布我想到的解决方案。

标签: list haskell tree higher-order-functions


【解决方案1】:

我会给你一个提示,在解析列表时演示一种有用的技术。

真正起作用的是这样的函数:

build' :: [(a,Int)] -> (LTree a, [(a,Int)])

也就是说,build' 返回一个 LTree a 以及它尚未使用的输入列表的其余部分。

在这种形式中,build' 的定义如下所示:

build' [] = error "oops - bad input list"
build' ((a,n):xs) =
  if we are at a leaf node, return (LTree a, xs)
  if we decide we need to fork, then return (Fork e f,zs)
    where
      (e,ys) = build' ((a,n):xs)  -- parse the left branch
      (f,zs) = build' ys          -- parse the right branch

请注意,这只是伪代码,缺少重要的细节,我将作为练习留下。

有趣的部分是在Fork 的情况下如何确定剩余的输入列表。 ys 是解析左分支后的剩余输入,并将其作为输入提供给build' 以获得右分支,并且对build' (zs) 的调用的剩余输入作为剩余返回来自原始build' 调用的输入。

更新:

要以起始值x 迭代函数f 直到达到特定条件p,请遵循以下公式:

iterateUntil p f x = if p x then x else iterateUntil p f (f x)

【讨论】:

  • 谢谢。这给了我一个想法。我用我提出的问题编辑了我的问题。也请提供您的解决方案。我总是喜欢看到相同问题的不同解决方案,这对我学习这门语言有很大帮助。
  • 好的,这是一个有用的功能。关于手头的问题,我不知道何时要停止迭代(例如,我不知道我的 p 在上面的定义中应该是什么)。
猜你喜欢
  • 2014-11-01
  • 1970-01-01
  • 2021-05-23
  • 2015-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多