简体   繁体   中英

Creating all Bool binary trees of size n

I'm trying to create all binary trees of size n, But can't think of a way to do it.

The Tree is defined like this

> data Tree :: * -> * where
>     Tip :: a -> Tree a
>     Bin :: Tree a -> Tree a -> Tree a  
>     deriving (Eq,Show)

A size of a tree is the number of Tips and Bins it has.

I need to create a function that gets an Int n and returns a list of all the trees of that size.

> getTrees :: Int -> [Tree Bool]

For example for getTrees 1 I should Get [Tip True, Tip False] since this is all the possible trees of size 1.

I can't think about a way to generate all the Trees of size n.

Let's start with the easy ones first: the trees of size one:

> getTrees :: Int -> [Tree Bool]
> genTrees 1 = [Tip True, Tip False]

Now, we have to think about greater Int s. So what about 2 ? It turns out that there does not exist any tree of size two, if both Bin and Tip increase the size. Any Bin leads to an additional size of 1 + k + j , where k and j must be valid tree sizes. One can see that this yields only trees of odd size.

We can therefore discard any invalid Int s before we continue:

> genTrees n | even n || n <= 0 = []
> genTrees n =

Now we know that our n is odd, and at least three. Therefore, we really have to use a Bin as a root for our other trees. Other trees? Well, remember the formula above? We need to generate two new trees with size j and k such that 1 + j + k = n . Luckily, we have a function to generate those trees, called genTrees . We can combine all in a single list comprehension:

>   [Bin l r | i <- [1,3..n-1], l <- genTrees i, r <- genTrees (n - 1 - i)]

Exercises

  • Prove that all used sizes in the list comprehension are valid, including the resulting tree size as well as the intermediate tree sizes.
  • While the second paragraph provided some motivation, it didn't provide a complete proof that valid trees must have odd size. Prove that statement.
  • Now count only Tip as size. What are now valid tree sizes?
  • Rewrite the algorithm above in order to generate trees where only Tip s contribute to the size (after all, only they have a payload).

ok I guess some dislike the way I tried to lead to the solution so without further due: here is one :

getTrees :: Int -> [Tree Bool]
getTrees 1 = [Tip True, Tip False]
getTrees n = do
  leftSize <- [0..n-2]
  let rightSize = (n-1) - leftSize
  left <- getTrees leftSize
  right <- getTrees rightSize
  return $ Bin left right

note:

you can see here that you will get problems with even-sized trees because those will at some time get to getTrees 0 which will pull leftSize <- [0..(-2)] and will end right there with an empty list

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM