Alberi binari
Un albero binario è un albero con nodi di tre tipi:
- nodi terminali, che non hanno figli
- nodi unari, che hanno un figlio ciascuno
- nodi binari, che hanno due figli ciascuno
Possiamo rappresentarli con la seguente grammatica, data in BNF (forma Backus – Naur):
<e> ::=
<terminal>
| <unary>
| <binary>
<terminal> ::=
"0"
<unary> ::=
"(1" <e> ")"
<binary> ::=
"(2" <e> " " <e> ")"
In questa grammatica i nodi sono indicati in preordine e ogni nodo è rappresentato da una cifra che è il numero di figli che ha.
Numeri di Motzkin
I numeri di Motzkin ( OEIS ) ( Wikipedia ) hanno molte interpretazioni, ma una interpretazione è che il n
numero di Motzkin è il numero di alberi binari distinti con n
nodi. Inizia una tabella di numeri Motzkin
N Motzkin number M(N)
1 1
2 1
3 2
4 4
5 9
6 21
7 51
8 127
...
per esempio M(5)
è 9, e sono i nove distinti alberi binari con 5 nodi
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)
Compito
Prendi un singolo intero positivo n
come input e output tutti i distinti alberi binari con n
nodi.
Esempi n
da 1 a 5 con parentesi inclusa per leggibilità
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)
Ingresso
L'input sarà un numero intero positivo.
Produzione
L'output dovrebbe essere una rappresentazione intelligibile degli alberi binari distinti con quel numero di nodi. Non è obbligatorio utilizzare la stringa esatta fornita dalla grammatica BNF sopra: è sufficiente che la sintassi utilizzata dia una rappresentazione inequivocabile degli alberi. Ad esempio, è possibile utilizzare []
anziché ()
un livello aggiuntivo di parentesi [[]]
anziché []
, parentesi esterne presenti o mancanti, virgole aggiuntive o senza virgole, spazi aggiuntivi, parentesi o nessuna parentesi, ecc.
Tutti questi sono equivalenti:
(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
Anche una variazione proposta da @xnor in un commento. Poiché esiste un modo per tradurlo in un formato comprensibile, è accettabile.
[[[]][]] is (2 (1 0) 0)
Per rendere questo più facile da capire convertire alcuni dei []
a ()
piacere in modo
[([])()]
Ora se inizi con
[]
quindi inserire un file binario che richiede due espressioni ottenute
[()()] which is 2
e quindi per il primo () inserisci un unario che necessita di un'espressione che ottieni
[([])()] which is 21
ma poiché []
o ()
senza parentesi interne può rappresentare 0 che non necessita di più espressioni, è possibile interpretarlo come
2100
Si noti che le risposte dovrebbero funzionare teoricamente con memoria infinita, ma ovviamente esauriranno la memoria per un input finito dipendente dall'implementazione.
Variazioni di output
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 possibile posto per verificare la presenza di alberi duplicati
Un posto per verificare la presenza di un duplicato è con M (5).
Questo albero è stato generato due volte per M (5) da M (4) alberi
(2 (1 0) (1 0))
il primo aggiungendo un ramo unario a
(2 (1 0) 0)
e in secondo luogo aggiungendo un ramo unario a
(2 0 (1 0))
Capire BNF
BNF è composto da semplici regole:
<symbol> ::= expression
dove a sinistra è racchiuso un nome simbolo <>
.
Sulla destra c'è l'espressione per costruire il simbolo. Alcune regole usano altre regole nella costruzione, ad es
<e> ::= <terminal>
e
può essere un terminal
e alcune regole hanno caratteri usati nella costruzione del simbolo, ad es
<terminal> ::= "0"
terminal
è solo il carattere zero.
Alcune regole hanno diversi modi per costruirle, ad es
<e> ::=
<terminal>
| <unary>
| <binary>
An e
può essere a <terminal>
o a <unary>
o a <binary>
.
E alcune regole sono una sequenza di parti, ad es
<unary> ::= "(1" <e> ")"
A unary
sono i personaggi (1
seguiti da ciò che può essere costruito per e
seguito da )
.
Si inizia sempre con la regola di partenza, che per questo <e>
.
Alcuni semplici esempi:
La sequenza più semplice è giusta 0
. Quindi iniziamo con la regola di partenza <e>
e vediamo che ci sono tre scelte:
<terminal>
| <unary>
| <binary>
quindi prendi il primo <terminal>
. Ora un terminale non ha scelta ed è 0
. Quindi sostituisci <terminal>
con 0
nella <e>
regola e il gioco è fatto.
Quindi il prossimo è (1 0)
. Inizia con <e>
e usa la regola <unary>
che ha
"(1" <e> ")"
Ora questo ha bisogno di un <e>
così torniamo a <e>
e facciamo una scelta di uno dei tre, questa volta scegliendo, <terminal>
che dà 0
. Sostituzione 0
in (1 <e> )
dà (1 0)
, e questo viene sostituito in <unary>
modo <e>
è (1 0)
.