Arboles binarios
Un árbol binario es un árbol con nodos de tres tipos:
- nodos terminales, que no tienen hijos
- nodos unarios, que tienen un hijo cada uno
- nodos binarios, que tienen dos hijos cada uno
Podemos representarlos con la siguiente gramática, dada en BNF (forma Backus-Naur):
<e> ::=
<terminal>
| <unary>
| <binary>
<terminal> ::=
"0"
<unary> ::=
"(1" <e> ")"
<binary> ::=
"(2" <e> " " <e> ")"
En esta gramática, los nodos se dan en preorden y cada nodo está representado por un dígito que es el número de hijos que tiene.
Números Motzkin
Los números de Motzkin ( OEIS ) ( Wikipedia ) tienen muchas interpretaciones, pero una interpretación es que el n
número de Motzkin es el número de árboles binarios distintos con n
nodos. Comienza una tabla de números de Motzkin
N Motzkin number M(N)
1 1
2 1
3 2
4 4
5 9
6 21
7 51
8 127
...
por ejemplo, M(5)
es 9, y los nueve árboles binarios distintos con 5 nodos son
1 (1 (1 (1 (1 0))))
2 (1 (1 (2 0 0)))
3 (1 (2 0 (1 0)))
4 (1 (2 (1 0) 0))
5 (2 0 (1 (1 0)))
6 (2 0 (2 0 0))
7 (2 (1 0) (1 0))
8 (2 (1 (1 0)) 0)
9 (2 (2 0 0) 0)
Tarea
Tome un solo entero positivo n
como entrada y salida de todos los árboles binarios distintos con n
nodos.
Ejemplos n
de 1 a 5 con paréntesis incluidos para facilitar la lectura
0
(1 0)
(1 (1 0))
(2 0 0)
(1 (1 (1 0)))
(1 (2 0 0))
(2 0 (1 0))
(2 (1 0) 0)
(1 (1 (1 (1 0))))
(1 (1 (2 0 0)))
(1 (2 0 (1 0)))
(1 (2 (1 0) 0))
(2 0 (1 (1 0)))
(2 0 (2 0 0))
(2 (1 0) (1 0))
(2 (1 (1 0)) 0)
(2 (2 0 0) 0)
Entrada
La entrada será un entero positivo.
Salida
El resultado debe ser una representación inteligible de los distintos árboles binarios con tantos nodos. No es obligatorio usar la cadena exacta dada por la gramática BNF anterior: es suficiente que la sintaxis utilizada dé una representación inequívoca de los árboles. Por ejemplo, podría usar en []
lugar de ()
un nivel adicional de paréntesis en [[]]
lugar de []
paréntesis externos presentes o faltantes, comas adicionales o sin comas, espacios adicionales, paréntesis o sin paréntesis, etc.
Todos estos son equivalentes:
(1 (2 (1 0) 0))
[1 [2 [1 0] 0]]
1 2 1 0 0
12100
(1 [2 (1 0) 0])
.:.--
*%*55
(- (+ (- 1) 1))
-+-11
También una variación propuesta por @xnor en un comentario. Como hay una manera de traducir esto a un formato que se pueda entender, es aceptable.
[[[]][]] is (2 (1 0) 0)
Para que sea más fácil de entender, convierta algunos de los []
que le ()
gusten
[([])()]
Ahora si comienzas con
[]
luego inserta un binario que necesita dos expresiones que obtienes
[()()] which is 2
y luego para el primer () inserta un unario que necesita una expresión que obtienes
[([])()] which is 21
pero como []
o ()
sin corchetes internos puede representar 0 que no necesita más expresiones, puede interpretarlo
2100
Tenga en cuenta que las respuestas deberían funcionar teóricamente con memoria infinita, pero obviamente se quedarán sin memoria para una entrada finita dependiente de la implementación.
Variaciones de salida
BNF xnor Christian Ben
b(t, b(t, t)) [{}{{}{}}] (0(00)) (1, -1, 1, -1)
b(t, u(u(t))) [{}{(())}] (0((0))) (1, -1, 0, 0)
b(u(t), u(t)) [{()}{()}] ((0)(0)) (1, 0, -1, 0)
b(b(t, t), t) [{{}{}}{}] ((00)0) (1, 1, -1, -1)
b(u(u(t)), t) [{(())}{}] (((0))0) (1, 0, 0, -1)
u(b(t, u(t))) [({}{()})] ((0(0))) (0, 1, -1, 0)
u(b(u(t), t)) [({()}{})] (((0)0)) (0, 1, 0, -1)
u(u(b(t, t))) [(({}{}))] (((00))) (0, 0, 1, -1)
u(u(u(u(t)))) [(((())))] ((((0)))) (0, 0, 0, 0)
Un posible lugar para buscar árboles duplicados
Un lugar para buscar un duplicado es con M (5).
Este árbol se generó dos veces para M (5) a partir de M (4) árboles
(2 (1 0) (1 0))
el primero agregando una rama unaria a
(2 (1 0) 0)
y segundo agregando una rama unaria a
(2 0 (1 0))
Entendiendo BNF
BNF se compone de reglas simples:
<symbol> ::= expression
donde a la izquierda hay un nombre de símbolo rodeado por <>
.
A la derecha está la expresión para construir el símbolo. Algunas reglas usan otras reglas en la construcción, por ej.
<e> ::= <terminal>
e
puede ser un terminal
y algunas reglas tienen caracteres que se usan para construir el símbolo, por ej.
<terminal> ::= "0"
terminal
es solo el caracter cero.
Algunas reglas tienen múltiples formas de construirlas, p. Ej.
<e> ::=
<terminal>
| <unary>
| <binary>
Un e
puede ser a <terminal>
o a <unary>
o a <binary>
.
Y algunas reglas son una secuencia de partes, por ej.
<unary> ::= "(1" <e> ")"
A unary
son los caracteres (1
seguidos de lo que se puede construir e
seguido de )
.
Siempre comienza con la regla de inicio, que para esto <e>
.
Algunos ejemplos simples:
La secuencia más simple es justa 0
. Entonces comenzamos con la regla de inicio <e>
y vemos que hay tres opciones:
<terminal>
| <unary>
| <binary>
así que toma el primero <terminal>
. Ahora una terminal no tiene opciones y es 0
. Así que reemplace <terminal>
con 0
en la <e>
regla y ya está.
Entonces el siguiente es (1 0)
. Comience con <e>
y use la regla <unary>
que tiene
"(1" <e> ")"
Ahora esto necesita un, <e>
así que volvemos <e>
y hacemos una elección de uno de los tres, esta vez eligiendo, lo <terminal>
que da 0
. Reemplazar 0
en (1 <e> )
da (1 0)
, y esto se reemplaza en <unary>
así <e>
es (1 0)
.