Binäre Bäume
Ein binärer Baum ist ein Baum mit drei Knotentypen:
- Endknoten, die keine Kinder haben
- unäre Knoten, die jeweils ein Kind haben
- Binärknoten, die jeweils zwei untergeordnete Knoten haben
Wir können sie mit der folgenden Grammatik darstellen, die in BNF (Backus-Naur-Form) angegeben ist:
<e> ::=
<terminal>
| <unary>
| <binary>
<terminal> ::=
"0"
<unary> ::=
"(1" <e> ")"
<binary> ::=
"(2" <e> " " <e> ")"
In dieser Grammatik sind die Knoten in vorrangiger Reihenfolge angegeben, und jeder Knoten wird durch eine Ziffer dargestellt, die die Anzahl der Kinder angibt, die er hat.
Motzkin-Zahlen
Motzkin-Zahlen ( OEIS ) ( Wikipedia ) haben viele Interpretationen, aber eine Interpretation ist, dass die n
th Motzkin-Zahl die Anzahl der verschiedenen Binärbäume mit n
Knoten ist. Eine Tabelle mit Motzkin-Nummern beginnt
N Motzkin number M(N)
1 1
2 1
3 2
4 4
5 9
6 21
7 51
8 127
...
zB M(5)
9, und die neun verschiedenen Binärbäumen mit 5 Knoten
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)
Aufgabe
Nehmen Sie eine einzelne positive Ganzzahl n
als Eingabe und geben Sie alle unterschiedlichen Binärbäume mit n
Knoten aus.
Beispiele für n
1 bis 5 mit Klammern zur besseren Lesbarkeit
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)
Eingang
Die Eingabe ist eine positive ganze Zahl.
Ausgabe
Die Ausgabe sollte eine verständliche Darstellung der verschiedenen Binärbäume mit so vielen Knoten sein. Es ist nicht obligatorisch, die exakte Zeichenfolge zu verwenden, die in der obigen BNF-Grammatik angegeben ist: Es reicht aus, wenn die verwendete Syntax eine eindeutige Darstellung der Bäume ergibt. ZB können Sie []
anstelle von ()
eine zusätzliche Ebene von Klammern [[]]
verwenden []
, äußere Klammern sind vorhanden oder fehlen, zusätzliche Kommas oder keine Kommas, zusätzliche Leerzeichen, Klammern oder keine Klammern usw.
Alle diese sind gleichwertig:
(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
Auch eine Variation von @xnor in einem Kommentar. Da es eine Möglichkeit gibt, dies in ein verständliches Format zu übersetzen, ist dies akzeptabel.
[[[]][]] is (2 (1 0) 0)
Um dies verständlicher zu machen, konvertieren einige der so []
zu ()
mögen
[([])()]
Beginnen Sie jetzt mit
[]
Fügen Sie dann eine Binärdatei ein, die zwei Ausdrücke benötigt, die Sie erhalten
[()()] which is 2
und dann füge für first () einen Unary ein, der einen Ausdruck benötigt, den du bekommst
[([])()] which is 21
aber da []
oder ()
ohne innere Klammer 0 darstellen kann, was keine weiteren Ausdrücke erfordert, können Sie es als interpretieren
2100
Beachten Sie, dass Antworten theoretisch mit unbegrenztem Speicher funktionieren sollten, bei einer implementierungsabhängigen endlichen Eingabe jedoch offensichtlich nicht genügend Speicher vorhanden ist.
Variationen der Ausgabe
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)
Ein möglicher Ort, um nach doppelten Bäumen zu suchen
Ein Ort, um nach einem Duplikat zu suchen, ist mit M (5).
Dieser eine Baum wurde zweimal für M (5) aus M (4) Bäumen generiert
(2 (1 0) (1 0))
die erste durch Hinzufügen eines unären Zweigs zu
(2 (1 0) 0)
und zweitens durch Hinzufügen eines unären Zweigs zu
(2 0 (1 0))
BNF verstehen
BNF besteht aus einfachen Regeln:
<symbol> ::= expression
wo auf der linken Seite ist ein Symbolname umgeben von <>
.
Rechts ist der Ausdruck für die Konstruktion des Symbols. Einige Regeln verwenden andere Regeln in der Konstruktion, z
<e> ::= <terminal>
e
kann sein a terminal
und einige Regeln haben Zeichen, die bei der Konstruktion des Symbols verwendet werden, z
<terminal> ::= "0"
terminal
ist nur das Zeichen Null.
Einige Regeln können auf mehrere Arten erstellt werden, z
<e> ::=
<terminal>
| <unary>
| <binary>
An e
kann a <terminal>
oder a <unary>
oder a sein <binary>
.
Und einige Regeln sind eine Folge von Teilen, z
<unary> ::= "(1" <e> ")"
A unary
sind die Zeichen, denen (1
folgt, wofür konstruiert werden kann, e
gefolgt von )
.
Sie beginnen immer mit der Startregel, die dafür gilt <e>
.
Einige einfache Beispiele:
Die einfachste Folge ist gerade 0
. Wir beginnen also mit der Startregel <e>
und stellen fest, dass es drei Möglichkeiten gibt:
<terminal>
| <unary>
| <binary>
also nimm den ersten <terminal>
. Jetzt hat ein Terminal keine Auswahl mehr und ist 0
. So ersetzen Sie <terminal>
mit 0
in der <e>
Regel und Sie sind fertig.
Dann ist der nächste (1 0)
. Beginnen Sie mit <e>
und verwenden Sie die Regel, <unary>
die hat
"(1" <e> ")"
Nun, das braucht eine, <e>
also kehren wir zurück <e>
und treffen eine Wahl von einer der drei, diesmal eine Wahl, <terminal>
die gibt 0
. Ersetzen 0
in (1 <e> )
gibt (1 0)
, und dies wird ersetzt in <unary>
so <e>
ist (1 0)
.