7
$\begingroup$

I've been trying to find an algorithm to list all binary trees of a given height $h$.

Note that I'm not trying to count them: the number of such trees is given in the OEIS (A001699).

All the algorithms that I have been able to see list all binary trees for a given number of nodes. A very inefficient way of solving the problem would proceed by checking all the trees with a number of nodes between $h+1$ and $2^{h+1}-1$, but this is not great at all.

Any pointers or references would be much appreciated.

$\endgroup$
  • 3
    $\begingroup$ The recurrence formulas imply such an algorithm. (In fact, not the formulas themselves, but rather their proof.) $\endgroup$ – Yuval Filmus May 18 '16 at 22:37
  • $\begingroup$ @YuvalFilmus Thanks for your comment. Do you mean a proof such as the one (using OGFs) provided at math.stackexchange.com/questions/1183643/…? I'm completely new to the field -- sorry to be slow. $\endgroup$ – Shiwen Yao May 18 '16 at 23:07
  • $\begingroup$ Your link has other formulas as well. Every reasonable recurrence would work. $\endgroup$ – Yuval Filmus May 19 '16 at 6:01
2
$\begingroup$

As hinted at in comments, just follow the recursive structure of binary trees.

We create a function listbt(h) that lists all binary trees of exactly height h.

type BTree = Leaf | Node(BTree, BTree)

def listbt 0 = { [Leaf] }
|   listbt h = {
  result = []
  for T in (listbt h-1) {
    for k in (0..h-1) {
      for t in (listbt k) {
         result += Node(T, t)
         result += Node(t, T) if k < h-1 || t != T
      }
    }
  }
  return result
}

Correctness follows with an elementary inductive proof over h.

If you memoize the results of listbt this is going to be as efficient as it gets; the sheer number of trees and thereby the number of checks t != T dominate.

Note that if you employ term sharing (i.e. only link t and T in Node(t, T) but do not copy them) you can reduce the size of the output significantly. That only makes sense if your BTree implementation is immutable, though.

$\endgroup$
-1
$\begingroup$

My first thought was that this only involves trees built from paths of length h, which are isomorphic to h-bit integers, but those are only a subset of what's needed. However starting with those all that's needed is to fill in each non-full intermediate node with trees that don't reach all the way to the leaf level.

That is: Enumerate the $2^{2^h}-1$ nonempty sets of h-bit integers and convert them into trees. Then for each tree T, for each non-full non-leaf node N (ie having one child only, since it's by definition already on a path to at least one leaf), attach all possible subtrees that don't reach the leaf level (height < height(N)-1, including the empty tree). Then output the cartesian product across all of the N's in T.

My assertion is that this generates all trees and doesn't generate any twice, since the not-reaching-leaf-level condition makes it impossible to start with one T and convert it into another T' with a different leaf of depth h.

$\endgroup$
  • 1
    $\begingroup$ That's really inefficient. $\endgroup$ – Yuval Filmus Jun 18 '16 at 18:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.