Tải bản đầy đủ (.doc) (17 trang)

Thuật toán biểu thức số học

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (116.74 KB, 17 trang )

Xử lý biểuthức số học
Lê Văn Chương
Trường THPT chuyên Phan Bội Châu - Nghệ An
Biểuthức số học được định nghĩa rất đơn giản và ngắn gọn như sau: Biểu thức số họclà
một chuỗi ký tự bao gồm:
-Một số nguyên không dấu hoặc có dấu, hoặc một tên biến đặt theo chuẩn củaPascal.
-Hai biểu thức số học nối với nhau bởi một dấu phép tính (+, -, *, hoặc /). Cóthể đặt trong
cặp dấu ngoặc đơn
Khi cho một biểu thứcthì thông thường ta phải kiểm tra xem biểu thức đã cho có là một
biểu thức đúngkhông. Để kiểm tra một biểu thức xem nó có đúng không ta cần kiểm tra
xem cácsố của nó có đúng không?, các biến trong đó có được đặt tên theo chuẩn củapascal
không? các phép tính có hợp logic toán học không? các dấu ngoặc đơn cóđúng không?
Trong các điều kiệntrên thì kiểm tra số, tên biến, các dấu chúng ta không để cập đến vì
chúng quádễ, một người mới bặt đầu học cũng có thể xử lý được. Chúng ta chỉ quan tâm
đếnxử lý các dấu phép tính và ngoặc đơn, đặc biệt là dấu ngoắc đơn bởi vì nó phứctạp và
khó xử lý nhất.
Bây giờ, chúng ta sẽxem xét một bài toán được gọi là đơn giản nhất trong xử lý biểu thức
số học.Nội dung của bài toán như sau:
Bài toán 1: Lập trình chươngtrình nhập vào một xâu ký tự chỉ gồm các dấu mở ngoặc và
đóng ngoặc đơn, sau đókiển tra tính đúng đăn của cách đặt dấu ngoặc. Một xâu ký tự đúng
là xâu thỏamãn:
- Số lần mở ngoặc đúng bằng số lần đóng ngoặc.
- Dấu mở ngoặc phải đứng trước (ở phía bên trái)dấu đóng ngoặc tương ứng.
Bài toán xử lý khôngkhó nhưng nó là nền tảng để chúng ta áp dụng vào các bài toán có
mức độ caohơn. Với bài này ta chỉ cần đọc dòng dữ liệu và tính số lần mở ngoặc có bằng
sốlần đóng ngoặc không? nếu không thì đó là biểu thức sai, nếu có thì kiểm tratiếp dấu mở
ngoặc có đứng trước dấu đóng ngoặc tương ứng không. Sau đây là đoạnchương trình
chính.
For i:=1 to length(s)do
Begin
If s[i] in [ ( , ) ] then


Begin
If s[i]= ( then inc(mn)else dec(mn);
If mn<0 then beginWriteln( Bieu thuc sai );Halt;End;
End;
If mn<>0 thenbegin Writeln( Bieu thuc sai );Halt;End;
Writeln( Bieu thucdung );
End;
Chúngta có thể nâng cấp chúng trình trên để kiểm tra một biểu thức đẩy đủ nhập vàocó
đúng không, đây chính là nội dung của bài toán 2.
Bài toán 2: Cho một xâu ký tựhãy kiểm tra xem xâu ký tự đó có là một biểu thức số học
đúng hay không, biểuthức được xem là đúng nếu nó thỏa mãn các điều kiện sau:
- Một số nguyên, hoặc một tên biến đặt theochuẩn của pascal.
- Hai biểu thức số học nối với nhau bởi một dấuphép tính (+, -, *, hoặc /), có thể đặt trong
một cặp dấu ngoặc đơn.
Với bài toán này, chúng ta không chỉkiểm tra dấu ngoặc đơn như bài trước mà còn kiểm tra
tính đúng đắn của các phéptính, các số, các biến, kiểm tra các dấu phép tính có phù hợp
không?
Thuật toán: Sử dụng biến dem đểkiểm tra các dấu ngoặc đơn có đúng không và biến dau
để kiểm tra tính đúng đắncủa dấu. Cách kiểm tra như sau:
Khởi tạo dem:=0 và dau:=1;
Gọi i là ký tự đang xét của xâu s:
- Nếu i là dấu '(' và biến dau có giá trị bằng 0thì đặt biến tăng biến dem lên 1;
- Nếu i là dấu ')' và trước i là một dấu phéptính thì chắc chắn đây là một biểu thức sai,
ngược lại giảm biến dem đi 1 đểbáo cho chương trình biết đã có 1 cặp dấu mở ngoặc đúng;
nếu dem<0 thi` s la`mo^.t bie^?u thu+'c sai bo+?i vi` so^' ky' tu+. ddo'ng ngoa(.c nhie^`u
ho+n so^' ky' tu+. mo+? ngoa(.c.
- Nếu i là một dấu phép tính(+, -, *, /) vàdau=1, có nghĩa là có 2 dấu liên tiếp nhau => đây
là biểu thức sai, ngượclại, nếu i là một dấu phép tính và trước đó chưa có dấu nào (dau = 0)
thì đặtdau:=1 để báo là đang xử lý biểu thức có dấu;
- Nếu i là các chữ cái A.. Z và a.. z thìđây chính là bắt đầu của 1 tên biến, ta phải xét i ở vị

trí cuối cùng của tênbiến này rồi xử lý tiếp:
- Nếu dau=0: S là biểuthức sai, bởi vì: ta khởi tao dau=1 nên với biến đầu tiên chương trình
sẽ chonó đúng và gán lại dau=0 rồi xử lý tiếp, đến khi gặp một dấu phép tính khác thìmới
khởi tạo dau=1 nên trong trường hợp này S là biểu thức sai.
- Nếu dau=1: Gán lạidau=0 và xử lý tiếp các ký tự sau tên biến đó.
Nếu i là các chữ số,ta phải xét vi trị mới của i là vị trí cuối cùng của số nguyên đó (nhiều
số):
- Nếu dau=0: tương tựtrên, đây là biểu thức sai
- Nếu dau=1: gán lạidau=0 và xử lý các ký tự sau số vừa đọc
Dưới đây là thủ tục kiểm tra một xâu có làbiểu thức số học hay không:
Functiontest(s: String): boolean;
Vari,dem,dau: integer;
Begin
test:=false;
dem:=0;
dau:=1;
i:=1;
While (i<=length(s)) do
begin
Case s[i] of
'(' : begin If dau=0 then exit; inc(dem); end;
')' : begin
If dau=1 then exit;
Dec(dem);
If dem<0 thenexit;
end;
'+','-','*','/' : If dau=1 then exit Else dau:=1;
'A'..'Z','á..'z': begin
If dau=0 then exit;
dau:=0;

While (i<LENGTH(S))AND(S[I+1]IN< p>
['á..'z','A'..'Z','0'..'9']) do inc(i);
end;
'0'..'9' : begin
If dau=0 then exit;
dau:=0;
While(i<>
['0'..'9']) doinc(i);
end;
End;
Inc(i);
end;
If (dem=0)and(dau=0) then test:=true;
End;
Để kiếm tra một xâu s có là biểu thức số học haykhông ta chỉ cần gọi:
If test(s) thenWriteln( La bieu thuc so hoc ) else Writeln( Bieu thuc sai );
Thôngthường sau khi kiểm tra tính đúng đắn của biểu thức thì người ra đề sẽ yêu cầu tính
biểu thức đó với các giá trịbiến cho trước. Có nhiều cách để tính giá trị biểu thức số học,
sau đây tôi sẽgiới thiệu cho các bạn phương pháp Ký pháp nghịch đảo Balan.
Ký pháp nghịch đảoBalan là một cách biểu diễn biểu thức toán học thông thường theo một
dạng khác,khá thuận lợi cho việc tính toán một biểu thức trong máy tính
Một biểu thức toán họcthông thường có thể được biến đổi thành dãy gồm các toán tử và
toán hạng, trongđó một toán tử được dùng để tính toán với 1 hoặc 2 toán hạng đứng trước
nótrong dãy đó.
Ví dụ: (T+R)*A biến đổi thành TR+A*
T+E*A biến đổi thành TEA*+
Có hai dạng ký pháp nghịch đảo Balan, preffix vàsuffix. Dạng trên là suffix.
Thuật toán để biến đổi biểu thức toán học thành dạng kýpháp nghịch đảo Balan như sau :
Ta sử dụng hai stack.Một dùng để lưu dạng Balan (nói tắt cho gọn), gọi là BtBalan, một
dùng để lưucác toán tử dùng trong quá trình chuyển biểu thức thành dạng Balan, gọi

làpheptinh. Kết quả được đưa vào BtBalan. Chỉ việc đọc lần lượt từ đầu đến cuốicủa
BtBalan thì sẽ được dạng ký pháp nghịch đảo Balan của biểu thức đã cho.
Ta sẽ đọc lần lượt từ đầu đến cuối biểu thức đãcho để xử lý:
- Nếu gặp dấu mở ngoặcthì Push nó vào stack pheptinh.
- Nếu gặp một toánhạng thì Push nó vào stack BtBalan.
- Nếu gặp một toán tửthì:
+ Nếu các toán tử đượclưu cuối cùng trong pheptinh có mức ưu tiên cao hơn thì lần lượt
Pop các toántử đó ra khỏi pheptinh, Push nó vào BtBalan. Làm vậy cho đến khi gặp phải
toántử có mức ưu tiên bằng hoặc thấp hơn nó thì dừng.
+ Push toán tử đangxét vào pheptinh.
+ Mức ưu tiên của cáctoán tử được quy định như sau: + -, *, / Dấu mở ngoặc được coi là
có mức ưutiên thấp nhất.
- Nếu gặp dấu đóngngoặc thì Pop toàn bộ các toán tử được lưu trong pheptinh, Push vào
BtBalan,cho đến khi gặp dấu mở ngoặc (được lưu trong pheptinh). Sau đó Pop luôn dấu
mởngoặc đó ra, vứt đi.
Sau khi đã thu đượcdạng kpnđ Balan rồi, tính toán như sau: tìm trong BtBalan một phép
toán đứngliền sau một toán hạng. Dùng phép toán đó áp dụng trên 1 hoặc 2 toán hạng
liềntrước nó. Thay một toán hạng bằng kết quả tìm được, xoá phần tử chứa toán hạngcòn
lại(nếu là 2 toán hạng) và phần tử chứa toán tử ra khỏi BtBalan. Tính đếnkhi không tìm
được toán tử nào nữa thì thôi.
Ta có bài toán tổng quát như sau: Cho xâu Slà biểu diễn của một biểu thức số học (với các
định nghĩa biểu thức số học nhưtrên). Hãy kiểm tra xem biểu thức đã cho có hợp lý
không? Nếu hợp lý thì tínhgiá trị biểu thức đã cho
Dữ liệu vào quy ước như sau:
- dòng đầu làbiểu thức cần tính toán
- Các dòng tiếptheo ghi giá trị các biến ở trong biểu thức cần tính (nếu có) theo cấu trúc: =
Dữ liệu ra: tệp bieuthuc.out gồm 1 dòngghi biểu thức và giá trị của biểu thức đó sau khi
tinh được.
Ví dụ:
((me*1984)+(tra*1983))/us

me=24
tra=29
us=04
Dưới đây là chương trình đầy đủ và chính xác về kiểmtra biểu thức số học và tính giá trị
biểu thức đó:
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+}
{$M16384,0,655360}
ProgramBieuthucsohoc;
Uses Crt;
Const
MN = 200;
fi = 'bieuthuc.inp';

×