Khi tôi nhìn thấy tiêu đề của câu hỏi đóng này , tôi nghĩ rằng nó trông giống như một thử thách golf mã thú vị. Vì vậy, hãy để tôi trình bày nó như vậy:
Thử thách:
Viết chương trình, biểu thức hoặc chương trình con, được đưa ra một biểu thức số học trong ký hiệu infix , như 1 + 2
, đưa ra biểu thức tương tự trong ký hiệu hậu tố , nghĩa là 1 2 +
.
(Lưu ý: Một thử thách tương tự đã được đăng vào đầu tháng 1. Tuy nhiên, tôi cảm thấy hai nhiệm vụ đủ khác nhau về chi tiết để biện minh cho thử thách riêng biệt này. Ngoài ra, tôi chỉ chú ý đến chủ đề khác sau khi gõ mọi thứ bên dưới, và tôi thích không chỉ vứt bỏ tất cả.)
Đầu vào:
Các đầu vào bao gồm một biểu thức số học ghi vào hợp lệ bao gồm số (số nguyên không âm biểu diễn dưới dạng chuỗi của một hoặc thập phân hơn chữ số), sự cân ngoặc để chỉ ra một subexpression nhóm, và bốn trung tố nhị phân các nhà khai thác +
, -
, *
và /
. Bất kỳ trong số này có thể được phân tách (và toàn bộ biểu thức được bao quanh) bởi một số ký tự khoảng trắng tùy ý, cần được bỏ qua. 1
Đối với những người thích ngữ pháp chính thức, đây là một ngữ pháp đơn giản giống như BNF xác định các đầu vào hợp lệ. Để đơn giản và rõ ràng, ngữ pháp không bao gồm các khoảng trắng tùy chọn, có thể xảy ra giữa hai mã thông báo bất kỳ (trừ các chữ số trong một số):
expression := number | subexpression | expression operator expression
subexpression := "(" expression ")"
operator := "+" | "-" | "*" | "/"
number := digit | digit number
digit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
1 Trường hợp duy nhất mà sự hiện diện của không gian có thể ảnh hưởng đến phân tích cú pháp là khi chúng tách hai số liên tiếp; tuy nhiên, vì hai số không được phân tách bởi một toán tử có thể xảy ra trong biểu thức trung tố hợp lệ, trường hợp này không bao giờ có thể xảy ra trong đầu vào hợp lệ.
Đầu ra:
Đầu ra phải là một biểu thức postfix tương đương với đầu vào. Biểu thức đầu ra nên bao gồm chỉ số và các nhà khai thác, với một nhân vật không gian duy nhất giữa mỗi cặp thẻ lân cận, như trong ngữ pháp sau (mà không bao gồm các không gian) 2 :
expression := number | expression sp expression sp operator
operator := "+" | "-" | "*" | "/"
number := digit | digit number
digit := "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
sp := " "
2 Một lần nữa để đơn giản, việc number
sản xuất trong ngữ pháp này thừa nhận các số có số 0 đứng đầu, mặc dù chúng bị cấm trong đầu ra theo các quy tắc dưới đây.
Ưu tiên điều hành:
Trong trường hợp không có dấu ngoặc đơn, các quy tắc ưu tiên sau sẽ được áp dụng:
- Các toán tử
*
và/
có quyền ưu tiên cao hơn+
và-
. - Các toán tử
*
và/
có quyền ưu tiên như nhau. - Các toán tử
+
và-
có quyền ưu tiên như nhau. - Tất cả các nhà khai thác là liên kết trái.
Ví dụ: hai biểu thức sau là tương đương:
1 + 2 / 3 * 4 - 5 + 6 * 7
((1 + ((2 / 3) * 4)) - 5) + (6 * 7)
và cả hai sẽ mang lại đầu ra sau:
1 2 3 / 4 * + 5 - 6 7 * +
(Đây là các quy tắc ưu tiên giống như trong ngôn ngữ C và trong hầu hết các ngôn ngữ có nguồn gốc từ nó. Chúng có thể giống với các quy tắc bạn được dạy ở trường tiểu học, ngoại trừ có thể có quyền ưu tiên tương đối *
và /
.)
Quy tắc khác:
Nếu giải pháp đưa ra là một biểu thức hoặc chương trình con, đầu vào sẽ được cung cấp và đầu ra được trả về dưới dạng một chuỗi. Nếu giải pháp là một chương trình hoàn chỉnh, nó sẽ đọc một dòng chứa biểu thức infix từ đầu vào tiêu chuẩn và in một dòng chứa phiên bản postfix sang đầu ra tiêu chuẩn.
Các số trong đầu vào có thể bao gồm các số 0 đứng đầu. Các số trong đầu ra không được có các số 0 đứng đầu (ngoại trừ số 0, sẽ là đầu ra dưới dạng
0
).Bạn không cần phải đánh giá hoặc tối ưu hóa biểu thức theo bất kỳ cách nào. Cụ thể, bạn không nên cho rằng các toán tử nhất thiết phải thỏa mãn bất kỳ danh tính liên kết, giao hoán hoặc đại số nào khác. Đó là, bạn không nên cho rằng ví dụ
1 + 2
bằng2 + 1
hoặc1 + (2 + 3)
bằng(1 + 2) + 3
.Bạn có thể giả sử rằng các số trong đầu vào không vượt quá 2 31 - 1 = 2147483647.
Các quy tắc này nhằm đảm bảo rằng đầu ra chính xác được xác định duy nhất bởi đầu vào.
Ví dụ:
Dưới đây là một số biểu thức đầu vào hợp lệ và các đầu ra tương ứng, được trình bày dưới dạng "input" -> "output"
:
"1" -> "1"
"1 + 2" -> "1 2 +"
" 001 + 02 " -> "1 2 +"
"(((((1))) + (2)))" -> "1 2 +"
"1+2" -> "1 2 +"
"1 + 2 + 3" -> "1 2 + 3 +"
"1 + (2 + 3)" -> "1 2 3 + +"
"1 + 2 * 3" -> "1 2 3 * +"
"1 / 2 * 3" -> "1 2 / 3 *"
"0102 + 0000" -> "102 0 +"
"0-1+(2-3)*4-5*(6-(7+8)/9+10)" -> "0 1 - 2 3 - 4 * + 5 6 7 8 + 9 / - 10 + * -"
(Ít nhất, tôi hy vọng tất cả những điều này là chính xác; tôi đã thực hiện chuyển đổi bằng tay, vì vậy những sai lầm có thể đã xuất hiện.)
Để rõ ràng, các đầu vào sau đây đều không hợp lệ; nó không có vấn đề gì giải pháp của bạn nếu cho họ (mặc dù, tất nhiên, ví dụ như trả lại một thông báo lỗi là đẹp hơn, chẳng hạn, tiêu thụ một số lượng vô hạn của bộ nhớ):
""
"x"
"1 2"
"1 + + 2"
"-1"
"3.141592653589793"
"10,000,000,001"
"(1 + 2"
"(1 + 2)) * (3 / (4)"
1 2 3 4 + *
như thế nào?
1 2 3 4 +
nghĩa là `1 + 2 + 3 + 4`.