Algoritmo para listar todas as árvores binárias de uma determinada altura

7

Eu tenho tentado encontrar um algoritmo para listar todas as árvores binárias de uma determinada altura h.

Observe que não estou tentando contá-las: o número dessas árvores é fornecido no OEIS ( A001699 ).

Todos os algoritmos que eu pude ver listam todas as árvores binárias para um determinado número de nós. Uma maneira muito ineficiente de resolver o problema seria verificar todas as árvores com um número de nós entreh+1 1 e 2h+1 1-1 1, mas isso não é nada bom.

Qualquer ponteiro ou referência seria muito apreciado.

Shiwen Yao
fonte
3
As fórmulas de recorrência implicam esse algoritmo. (Na verdade, não as próprias fórmulas, mas sim a sua prova.)
Yuval Filmus
@YuvalFilmus Obrigado pelo seu comentário. Você quer dizer uma prova como a (usando OGFs) fornecida em math.stackexchange.com/questions/1183643/… ? Sou completamente novo em campo - desculpe por ser lento.
Shiwen Yao
Seu link também tem outras fórmulas. Toda recorrência razoável funcionaria.
Yuval Filmus

Respostas:

2

Como sugerido nos comentários, basta seguir a estrutura recursiva das árvores binárias.

Criamos uma função listbt(h)que lista todas as árvores binárias exatamente da alturah .

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
}

A correção segue com uma prova indutiva elementar h.

Se você memorizar os resultados de listbt serão tão eficientes quanto possível; o grande número de árvores e, assim, o número de verificações t != Tdominam.

Observe que, se você empregar o compartilhamento de termos (ou seja, apenas vincular te inserir T, Node(t, T)mas não copiá-los), poderá reduzir significativamente o tamanho da saída. Isso só faz sentido se sua BTreeimplementação for imutável.

Rafael
fonte
-1

Meu primeiro pensamento foi que isso envolve apenas árvores construídas a partir de caminhos de comprimento h, que são números inteiros isomórficos a h-bit, mas esses são apenas um subconjunto do que é necessário. No entanto, começando com tudo o que é necessário, é preencher cada nó intermediário não cheio com árvores que não atingem todo o caminho até o nível da folha.

Ou seja: Enumere o 22h-1 1conjuntos não vazios de números inteiros de h e convertê-los em árvores. Em seguida, para cada árvore T, para cada nó não-folha não cheio N (ou seja, ter apenas um filho, já que por definição já está no caminho de pelo menos uma folha), anexe todas as subárvores possíveis que não atinjam o nível da folha (altura <altura (N) -1, incluindo a árvore vazia). Em seguida, imprima o produto cartesiano em todos os N's em T.

Minha afirmação é que isso gera todas as árvores e não gera duas vezes, uma vez que a condição de não atingir o nível da folha torna impossível iniciar com um T e convertê-lo em outro T 'com uma folha diferente de profundidade h.

KWillets
fonte
11
Isso é realmente ineficiente.
Yuval Filmus