Cây nhị phân
Cây nhị phân là cây có các nút gồm ba loại:
- các nút thiết bị đầu cuối, không có con
- các nút unary, mỗi nút có một con
- các nút nhị phân, có hai con mỗi
Chúng ta có thể biểu diễn chúng bằng ngữ pháp sau, được đưa ra trong BNF (dạng BackusIP Naur):
<e> ::=
<terminal>
| <unary>
| <binary>
<terminal> ::=
"0"
<unary> ::=
"(1" <e> ")"
<binary> ::=
"(2" <e> " " <e> ")"
Trong ngữ pháp này, các nút được đưa ra theo thứ tự và mỗi nút được biểu thị bằng một chữ số là số con mà nó có.
Số Motzkin
Số Motzkin ( OEIS ) ( Wikipedia ) có nhiều cách hiểu, nhưng một cách giải thích là n
số Motzkin là số cây nhị phân riêng biệt có n
nút. Một bảng số Motzkin bắt đầu
N Motzkin number M(N)
1 1
2 1
3 2
4 4
5 9
6 21
7 51
8 127
...
ví dụ M(5)
là 9 và chín cây nhị phân riêng biệt có 5 nút là
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)
Bài tập
Lấy một số nguyên dương duy nhất n
làm đầu vào và đầu ra tất cả các cây nhị phân riêng biệt có n
các nút.
Ví dụ n
từ 1 đến 5 có dấu ngoặc đơn để dễ đọc
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)
Đầu vào
Đầu vào sẽ là một số nguyên dương.
Đầu ra
Đầu ra phải là một đại diện dễ hiểu của các cây nhị phân riêng biệt với nhiều nút đó. Không bắt buộc phải sử dụng chuỗi chính xác được cung cấp bởi ngữ pháp BNF ở trên: cú pháp được sử dụng cung cấp một biểu diễn rõ ràng của các cây. Ví dụ: bạn có thể sử dụng []
thay vì ()
, một mức dấu ngoặc bổ sung [[]]
thay vì []
dấu ngoặc đơn bên ngoài có hoặc thiếu, dấu phẩy thừa hoặc không có dấu phẩy, dấu cách thêm, dấu ngoặc đơn hoặc không dấu ngoặc đơn, v.v.
Tất cả những thứ này là tương đương:
(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
Cũng là một biến thể được xác định bởi @xnor trong một bình luận. Vì có một cách để dịch cái này sang một định dạng có thể hiểu được nên nó được chấp nhận.
[[[]][]] is (2 (1 0) 0)
Để làm điều này dễ hiểu chuyển đổi một số []
để ()
thích quá
[([])()]
Bây giờ nếu bạn bắt đầu với
[]
sau đó chèn một nhị phân cần hai biểu thức bạn nhận được
[()()] which is 2
và sau đó cho lần đầu tiên () chèn một unary cần một biểu thức bạn nhận được
[([])()] which is 21
nhưng vì []
hoặc ()
không có dấu ngoặc trong có thể biểu thị 0 mà không cần thêm biểu thức nào bạn có thể hiểu nó là
2100
Lưu ý rằng các câu trả lời sẽ hoạt động trên lý thuyết với bộ nhớ vô hạn, nhưng rõ ràng sẽ hết bộ nhớ cho đầu vào hữu hạn phụ thuộc vào việc thực hiện.
Biến thể đầu ra
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)
Một nơi có thể để kiểm tra các cây trùng lặp
Một nơi để kiểm tra trùng lặp là với M (5).
Cây này được tạo hai lần cho M (5) từ M (4) cây
(2 (1 0) (1 0))
đầu tiên bằng cách thêm một nhánh unary vào
(2 (1 0) 0)
và thứ hai bằng cách thêm một nhánh unary vào
(2 0 (1 0))
Hiểu về BNF
BNF bao gồm các quy tắc đơn giản:
<symbol> ::= expression
trong đó bên trái là một tên biểu tượng được bao quanh bởi <>
.
Bên phải là biểu thức để xây dựng biểu tượng. Một số quy tắc sử dụng các quy tắc khác trong xây dựng, ví dụ
<e> ::= <terminal>
e
có thể là một terminal
và một số quy tắc có các ký tự được sử dụng để xây dựng biểu tượng, ví dụ:
<terminal> ::= "0"
terminal
chỉ là số không.
Một số quy tắc có nhiều cách để xây dựng chúng, ví dụ:
<e> ::=
<terminal>
| <unary>
| <binary>
An e
có thể là a <terminal>
hoặc a <unary>
hoặc a <binary>
.
Và một số quy tắc là một chuỗi các bộ phận, ví dụ
<unary> ::= "(1" <e> ")"
A unary
là các ký tự (1
theo sau bởi những gì có thể được xây dựng để e
theo sau )
.
Bạn luôn bắt đầu với quy tắc bắt đầu, mà cho việc này <e>
.
Một số ví dụ đơn giản:
Trình tự đơn giản nhất là chỉ 0
. Vì vậy, chúng tôi bắt đầu với quy tắc bắt đầu <e>
và thấy rằng có ba lựa chọn:
<terminal>
| <unary>
| <binary>
vì vậy hãy là người đầu tiên <terminal>
. Bây giờ một thiết bị đầu cuối không có sự lựa chọn và là 0
. Vì vậy, thay thế <terminal>
bằng 0
trong <e>
quy tắc và bạn đã hoàn tất.
Sau đó, tiếp theo là (1 0)
. Bắt đầu với <e>
và sử dụng quy tắc <unary>
có
"(1" <e> ")"
Bây giờ điều này cần một <e>
vì vậy chúng tôi quay trở lại <e>
và đưa ra lựa chọn của một trong ba, lần này là lựa chọn, <terminal>
mang lại 0
. Thay thế 0
vào (1 <e> )
cho (1 0)
, và điều này được thay thế vào <unary>
nên <e>
là (1 0)
.