haskell - 生成所有可能的树

标签 haskell binary-tree list-comprehension catalan

给定以下数据类型定义:

data FormTree = Empty | Node FormTree FormTree deriving Show

我想编写一个函数,它生成一个无限列表,其中包含按长度排序的所有可能的树,例如节点数量。

下面的代码几乎满足了我的需要,但它只是通过每次插入额外的节点来使右侧的树下降,但我需要它在两侧之间交替。

allPossibleTrees :: [FormTree]
allPossibleTrees = Empty : [Node x y | x <- recursive, y <- recursive]
    where recursive = allPossibleTrees

执行中

take 5 allPossibleTrees

给出:

[Empty,Node Empty Empty,Node Empty (Node Empty Empty),Node Empty (Node Empty (Nodes Empty Empty)),Node Empty (Node Empty (Node Empty (Node Empty Empty)))]

但它应该是这样的:

[Empty,Node Empty Empty,Node (Node Empty Empty) Empty,Node Empty (Node Empty Empty),Node (Node Empty Empty) (Node Empty Empty)]

最佳答案

这是一个很好的技巧,让人想起标准的斐波那契数字技巧。我们将建立一个惰性列表;列表中的每个成员都是具有给定节点数的所有树的列表。只有一棵没有节点的树,,这将作为我们的基本情况。要构建具有 n 个节点的所有树,我们假设我们已经知道如何使用 012 构建树, ..., n-1 个节点。然后,我们将不确定地选择总和为 n-1 的配对,并将一个 Node 放在顶部。

在代码中:

import Control.Monad
import Data.List

sizes :: [[FormTree]]
sizes = [Empty] : (map go . drop 1 . inits) sizes where
    go smaller = do
      (ls, rs) <- zip smaller (reverse smaller)
      liftM2 Node ls rs

然后,如果需要的话,我们可以简单地定义allPossibleTrees = concatsized。前几个条目:

*Main> mapM_ print (take 4 sizes)
[Empty]
[Node Empty Empty]
[Node Empty (Node Empty Empty),Node (Node Empty Empty) Empty]
[Node Empty (Node Empty (Node Empty Empty)),Node Empty (Node (Node Empty Empty) Empty),Node (Node Empty Empty) (Node Empty Empty),Node (Node Empty (Node Empty Empty)) Empty,Node (Node (Node Empty Empty) Empty) Empty]

我们可以进行快速健全性检查:

*Main> take 10 (map length sizes)
[1,1,2,5,14,42,132,429,1430,4862]

...这确实是前十个 Catalan numbers ,所以我们可能是对的!

关于haskell - 生成所有可能的树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28100650/

相关文章:

haskell - "Any function on finite lists that is defined by pairing the desired result with the argument list can always be redefined in terms of fold"

algorithm - 从左到右和自下而上构造和打印二叉树(不平衡二叉树)的元素

C++ 使用 vector 的二叉树

python - 有没有更好的方法可以在 Python 中使用键但没有值将列表转换为字典?

unit-testing - Haskell 模块中的简单测试用例

haskell - 生成集合的子集。懒惰?

haskell - 为什么 Haskell 在读取 Num 时似乎默认读取 Int?

C - 从二叉树中删除节点

python - 转换字典列表,根据键组合列表项

python - 将列表理解表达式拆分为多行以更好地了解发生了什么?