生成所有可能的树

Generate All Possible Trees

给定以下数据类型定义:

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)]

列表理解

[ (x,y) | x<-[1..] , y<-[1..] ]

首先考虑 x=1 并为所有可能的 y 构建所有对 (1,y)。然后是 x=2 和所有 (2,y) 对。等等。

然而,(1,y)对有无限多,所以x=2只会在无限长的时间后才会被考虑——也就是说,根本不会。

您的代码遇到了同样的问题。

要查看可能的解决方案,您可以参考this related question利用Omega monad在所有情况下实现公平调度。

一种方法是跟踪树的大小(即使用的 Node 构造函数的数量。)

假设你有一个像这样的函数,它使用 n 个节点构造函数返回树:

treesOfSize :: Int -> [FormTree]

那么allTrees可以定义为:

allTrees = concatMap treesOfSize [0..]

treesOfSize的定义是可以递归定义的,我会让你弄清楚:

treesOfSize 0 = [Empty]
treesOfSize n = [ Node t1 t2 | ... ]

这是一个不错的技巧,让人联想到标准的斐波那契数字技巧。我们将构建一个惰性列表;列表的每个成员将是具有给定节点数的所有树的列表。只有一棵没有节点的树,Empty,这将作为我们的基本情况。要构建具有 n 个节点的所有树,我们假设我们已经知道如何构建具有 012、...、[=18 的树=] 节点。然后我们将不确定地选择一对总和为 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 = concat sizes 如果需要的话。前几条:

*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,所以我们可能猜对了!

control-monad-omega 库似乎可以用您的原始代码解决问题:

{-# LANGUAGE MonadComprehensions #-}

import Control.Monad.Omega

data Empty = Empty | Node Empty Empty deriving Show

allPossibleTrees :: [Empty]
allPossibleTrees = Empty : 
    runOmega [Node x y | x <- each allPossibleTrees, y <- each allPossibleTrees]

前 10 棵树我觉得不错:

*Main> mapM_ print $ take 10 allPossibleTrees 
Empty
Node Empty Empty
Node Empty (Node Empty Empty)
Node (Node Empty Empty) Empty
Node Empty (Node Empty (Node Empty Empty))
Node (Node Empty Empty) (Node Empty Empty)
Node (Node Empty (Node Empty Empty)) Empty
Node Empty (Node (Node Empty Empty) Empty)
Node (Node Empty Empty) (Node Empty (Node Empty Empty))
Node (Node Empty (Node Empty Empty)) (Node Empty Empty)