Reverse Polish Notation

3 965 1
Reverse Polish Notation

Đang tải... (xem toàn văn)

Thông tin tài liệu

Reverse Polish Notation

Reverse Polish Notation - Thuật toán tính giá trị biểu thứcNgô Minh ĐứcReverse Polish Notation (ký pháp nghịch đảo Ba Lan) là một loại ký pháp toán học dùng để biểu thị biểu thức đại số, rất thuận lợi trong giải thuật tính giá trị biểu thức, có nghĩa là bạn nhập vào một chuỗi, chẳng hạn ″(1+2)*3″, chương trình sẽ tính ra kết qủa bằng 9.Reverse Polish Notation (gọi tắt là RPN) có hai loại, tiền tố (preffix) và hậu tố (suffix), trong bài này tôi chỉ đề cập đến dạng suffix.Để hiểu rõ hơn và dễ dàng tiếp cận với thuật toán này trước tiên chúng ta xét một ví dụ đơn giản sau đây:Chẳng hạn xét biểu thức sau: (1 + 2) x 3 thì dạng RPN - hậu tố - của biểu thức trên là: 1 2 + 3 xChương trình có thể tính toán rất dễ dàng với biểu thức dạng RPN. Bạn để ý trong biểu thức RPN không còn dấu ngoặc nữa, khi tính toán chỉ cần duyệt các toán tử từ trái sang phải và thực hiện với các toán hạng đứng trước nó.Đây là mô tả qúa trình tính toán biểu thức RPN trên:Bước 1: Duyệt đến dấu +, ngừng lại.Bước 2: Cộng hai toán hạng đứng trước nó: 1+2=3.Bước 3: Xóa các phần tử 1, 2, + thay bằng số 3Quay lại bước 1: Duyệt đến dấu x, ngừng lạiQuay lại bước 2: Nhân hai toán hạng đứng trước nó: 3x3=9Quay lại bước 3: Thay các phần tử 3, 3, x bởi số 9. Chỉ còn một phần tử nên kết thúc.Kết qủa chính là phần tử duy nhất còn lại: Đó là số 9Do đó vấn đề chỉ còn là chuyển biểu thức từ dạng thông thường sang dạng RPN. Sau đây tôi sẽ trình bày giải thuật chuyển đổi dưới hai phần.1. Phần cơ bản.Giải thuật này do các bạn trên TTVNOnline (www.ttvnol.com) và Diễn Đàn Tin Học (www.diendantinhoc.com) cung cấp.Xin các bạn chú ý một điều là: các phần tử trong biểu thức được chia ra làm hai loại: toán hạng (số) và toán tử (bao gồm dấu và hàm)Trong các loại toán tử, chúng ta cần lưu ý đến toán tử cộng trừ một ngôi (unary plus/minus). Đây là một loại toán tử chỉ tác dụng lên một toán hạng đứng trước nó, khác với toán tử cộng trừ bình thường tác dụng lên hai toán hạng đứng trước nóví dụ: -2 + 5 thì ″-″ là toán tử một ngôi, ″+″ là toán tử bình thườngĐể xác định ″+″, ″-″ là một ngôi hay hai ngôi, khi duyệt biểu thức ta chỉ cần xem phần tử đứng trước nó là số hay là một toán tử khácMức ưu tiên của các toán tử (từ nhỏ đến lớn): (, +, -, *, /, ^, + một ngôi, - một ngôiThuật toán: Ta sử dụng hai stack (ngăn xếp): rpnStack dùng để lưu dạng RPN, oprStack dùng để tạm lưu các toán tử trong qúa trình xử lý. Đọc lần lượt từ đầu đến cuối biểu thức để xử lý theo từng loại: Dấu mở ngoặc: đưa vào oprStackToán hạng: đưa vào rpnStack Toán tử: Trong trường hợp này ta phải xét toán tử đang ở trên cùng (được đưa vào cuối cùng) trong oprStack: nếu mức ưu tiên cao hơn toán tử đang xét thì chuyển toán tử đó sang rpnStack; tiếp tục làm như vậy cho đến khi được toán tử có mức ưu tiên nhỏ hơn hoặc bằng toán tử đang xét; cuối cùng đưa toán tử đang xét vào oprStack Dấu đóng ngoặc: lần lượt chuyển các toán tử được lưu trong oprStack sang rpnStack; cho đến khi gặp dấu mở ngoặc thì dừng lại và xóa dấu mở ngoặc đó khỏi oprStackLưu ý: Khi viết chương trình chỉ duyệt được từng ký tự, do đó phải thêm phần nhận biết nhóm ký tự hợp thành một số (hoặc một tên biến)Ví dụ: 564 + 4, khi bắt đầu duyệt từ ký tự ″5″ sẽ nhận biết luôn số ″564″ và nhảy đến ký tự thứ tư.Đây là những bước cơ bản của thuật toán, sau khi chuyển đổi xong, bạn đọc từ đầu đến cuối (từ dưới lên trên) trong rpnStack sẽ thu được dạng RPN.Sau khi thu được dạng RPN, cách tính toán như sau:Tìm toán tử đầu tiên trong rpnStack và áp dụng tính với các toán hạng đứng trước nó. Sau đó, xóa toán tử và các toán hạng đã tính, thay bằng kết qủa tính được.Tiếp tục cho đến khi nào không còn toán tử để tính nữa, kết qủa của biểu thức chính là phần tử đầu tiên của rpnStack.2. Phần mở rộng.Trên đây chỉ là các bước cơ bản, tùy theo sự khéo léo của bạn mà có thể cải tiến giải thuật để tính được những biểu thức phức tạp hơn. Tôi xin trình bày một số mở rộng về giải thuật để tính phân số, hỗn số và tính hàm nhiều tham số (chẳng hạn max(1,2,3) =3)* Tính phân số, hỗn số.Ta đặt thêm hai toán tử, gọi là oprFraction (dấu phân số, giả sử là ″~″) và oprMixed (dấu hỗn số)oprMixed chỉ là một toán tử ″ảo″ được thêm vào cho thuận lợi trong qúa trình xử lý.Độ ưu tiên của toán tử: (, +, -, *, /, ~, ^, + một ngôi, - một ngôi).Trước khi đưa toán tử phân số vào rpnStack ta cần xét phần tử trên cùng trong rpnStack như sau:Nếu cũng là toán tử phân số: gộp toán tử này và toán tử phân số đang xét thành toán tử hỗn số.Nếu là toán tử hỗn số: cho chương trình báo lỗi. Trong trường hợp còn lại: đưa toán tử phân số vào rpnStack bình thường.Thêm phần xử lý dấu phân số và dấu hỗn số vào thủ tục tính toán như sau:Dấu phân số: gọi hàm khởi tạo fraction (gọi chung cho phân số/hỗn số) từ hai toán hạng đứng trước.Dấu hỗn số: gọi hàm khởi tạo fraction từ ba toán hạng đứng trước.Fraction có thể được quy định theo kiểu String (vd ″1~3″, ″17~18″,″1~1~2″.…).Trong khi tính toán với fraction nên đổi hết ra phân số (chỉ gồm tử và mẫu), đến khi xuất kết qủa mới đổi thành hỗn số hoặc giữ nguyên tùy theo lựa chọn của người dùng.Lúc này, khi thực hiện các phép toán + - * /, có thể làm như sau (theo kiểu máy tính Casio):Ta xét hai toán hạng của phép tính:Nếu gồm một số lẻ thập phân: đổi hết ra số thập phân (nếu toán tử còn lại là phân số) và tính.Nếu chỉ gồm số nguyên và phân số: tính theo phân số Bạn phải tự viết một module để xử lý phân số (cộng, trừ, nhân, chia, khởi tạo, .)Để xử lý loại biểu thức phức tạp hơn (chẳng hạn (1~3)~2 = 1~6) thì cần phải thêm một số bước nữa. Bạn có thể liên hệ với tôi để nhận đựơc mã nguồn.* Hàm nhiều tham số.Phần này trình bày cách xử lý các hàm nhiều tham số, chẳng hạn như max(1,2,3) hay uscln(5,6,12,30),v.v…Ta đặt thêm một toán tử gọi là oprComma (dấu phẩy), độ ưu tiên chỉ đứng trên dấu mở ngoặc (áp chót). Trong khi chuyển đổi cũng xử lý với oprComma như những toán tử khácĐể mô tả thuật giải, ta xét ví dụ sau: max(1,2,3).Sau công đoạn chuyển đổi ta có: 1 2 3 , , max.Khi gặp dấu ″,″ ta gộp hai toán hạng đứng trước nó vào một mảng.Như vậy sau bước 1 ta có: 1(2,3), max (ký hiệu (2,3) là chỉ mảng).Gặp dấu ″,″ tiếp theo ta gộp luôn phần tử đầu tiên vào phần tử ″mảng″ thứ hai:Như vậy sau bước 2 ta có (1,2,3) max.Do đó hàm ″max″ đã trở nên được thực hiện trên một tham số duy nhất, tham số đó lại là một mảng các đối số. Để tính toán được ta phải xây dựng các hàm xử lý trên mảng đối số.Lưu ý: Cách làm này chưa hay và không thích hợp với những trình biên dịch như Turbo Pascal. Bạn có thể liên hệ với tôi theo địa chỉ: attilathehunvn @yahoo.com để nhận được mã nguồn (bằng VB và VB. NET). Tôi mô tả giải thuật này trong một class, gọi là ″Evaluator″, bao gồm một thủ tục chính là Eval(). Bạn có thể gọi thủ tục này từ bất kỳ module nào, chẳng hạn Eval(″1~3+2″) sẽ cho kết qủa là ″2~1~3″.Class này được áp dụng trong chương trình Quick Calculator 1.0 của tác giả. Rất mong được các bạn giúp đỡ để hoàn thiện thêm giải thuật . Reverse Polish Notation - Thuật toán tính giá trị biểu thứcNgô Minh ĐứcReverse Polish Notation (ký pháp nghịch đảo Ba Lan). một chuỗi, chẳng hạn ″(1+2)*3″, chương trình sẽ tính ra kết qủa bằng 9 .Reverse Polish Notation (gọi tắt là RPN) có hai loại, tiền tố (preffix) và hậu tố (suffix),

Ngày đăng: 11/09/2012, 13:53

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan