1. Trang chủ
  2. » Công Nghệ Thông Tin

Reverse Polish Notation

3 967 1
Tài liệu đã được kiểm tra trùng lặp

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 3
Dung lượng 37 KB

Nội dung

Reverse Polish Notation

Trang 1

Reverse Polish Notation - Thuật toán tính giá trị biểu thức

Ngô Minh Đức

Reverse 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 x

Chươ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ố 3

Quay lại bước 1: Duyệt đến dấu x, ngừng lại

Quay lại bước 2: Nhân hai toán hạng đứng trước nó: 3x3=9

Quay 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ố 9

Do đó 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ác

Mức ưu tiên của các toán tử (từ nhỏ đến lớn): (, +, -, *, /, ^, + một ngôi, - một ngôi

Thuậ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 oprStack

Toán hạng: đưa vào rpnStack

Trang 2

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 oprStack

Lư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ố

Trang 3

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

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

TỪ KHÓA LIÊN QUAN

w