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

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

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

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 17
Dung lượng 74,5 KB

Nội dung

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

Trang 1

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

Trang 2

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ấụ 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 thì s làmột biểu thức sai bởi vì số ký tự đóng ngoặc nhiều hơn số ký tự mở ngoặc

Trang 3

- 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

Trang 4

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:

Trang 5

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

Trang 6

- 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

Trang 7

MN = 200;

fi = 'bieuthuc.inp';

fo = 'bieuthuc.out';

Type

mangst = array [1 MN] of string[9]; manglg = array [1 MN] of longint; mangit = array [1 MN] of integer; Var

tenbien,ten : mangst;

Value,tri,stack : manglg;

p : mangit;

s,Hangso,Bienso : string;

so,sb,st,ip,sst,Sobien: longint; sym : char;

f,g : text;

ProcedureDocbien;

Var

s1: string;

i: integer;

Begin

Sobien:=0;

While not Eof(f) do

begin

Trang 8

i:=1; Inc(Sobien);

Tenbien[Sobien]:='';

While s1[i]<>'=' do

begin

If s1[i]<>' ' thenTenbien[Sobien]:=Tenbien[Sobien]+UpCase(s1[i]); Inc(i);

end;

Value[Sobien]:=0;

While i<=length(s1) do

begin

If s1[i] in ['0' '9'] then

Value[Sobien]:=Value[Sobien]*10+ord(s1[i])-ord('0');

Inc(i);

end;

end;

For i:=1 to Sobien do

While length(tenbien[i])<8 dotenbien[i]:=tenbien[i]+' ';

End;

ProcedureLoi;

Begin

Writeln('LOI: Khong hop lý);

End;

Trang 9

Var

i: integer;

Begin

Assign(f,fi); Reset(f);

Readln(f,s);

Docbien;

Close(f);

For i:=1 to length(s) dos[i]:=UpCase(s[i]); sb:=1; st:=0; ip:=0; sst:=0;

End;

ProcedureCach;

Begin

While s[sb]=' ' do Inc(sb);

End;

FunctionDoiso: longint;

Begin

so:=0;

While s[sb] in ['0' '9'] do

begin

so:=so*10+(ord(s[sb])-ord('0'));

Inc(sb);

end;

Trang 10

ProcedureNhanbien;

Begin

Bienso:='';

While s[sb] in ['Á 'Z','0' '9'] do

begin

Bienso:=Biensơs[sb]; Inc(sb);

end;

While length(Bienso)<8 doBienso:=Biensớ '; End;

ProcedurePheptinh;

Begin

Cach;

Case s[sb] of

'(' : beginsym:=s[sb]; Inc(sb); end;

')' : begin sym:=s[sb]; Inc(sb); end;

'+' : begin sym:=s[sb]; Inc(sb); end;

'-' : begin sym:=s[sb]; Inc(sb); end;

'*' : begin sym:=s[sb]; Inc(sb); end;

'/' : begin sym:=s[sb]; Inc(sb); end;

'%' : begin sym:=s[sb]; Inc(sb); end;

'0' '9': begin sym:='0'; Doiso; end;

'Á 'Z': begin sym:='Á; Nhanbien; end;

Trang 11

Else sym:=#0;

End;

End;

FunctionTimso: integer; Var

i: integer;

Begin

For i:=1 to st do

If ten[i]=' ' then

If tri[i]=so then

begin

Timso:=i;

exit;

end;

Inc(st); ten[st]:=' ';

tri[st]:=so;

Timso:=st;

End;

FunctionTimbien: integer; Var

i: integer;

Begin

For i:=1 to st do

Trang 12

If pos(Bienso,ten[i])>0 then begin

Timbien:=i;

exit;

end;

Inc(st); ten[st]:='?'+Bienso; Timbien:=st;

End;

FunctionTimdau(c: char): integer; Begin

Case c of

'+':Timdau :=-1;

'-': Timdau:=-2;

'*': Timdau:=-3;

'/': Timdau:=-4;

'%': Timdau:=-5;

'#': Timdau:=-6;

End;

End;

ProcedureBieuthuc;

Var

i: integer; daubt: char;

Procedure Hangtu;

Trang 13

i: integer;

Procedure Nhantu;

Var

i: integer;

Begin

While sym in ['0','A','('] do

begin

Case sym of

'0': begin i:=Timso; Inc(ip); p[ip]:=i; end; 'A': begin i:=Timbien;Inc(ip); p[ip]:=i; end; '(': begin

Pheptinh;Bieuthuc;

If sym<>')'then Loi;

end;

End;

Pheptinh;

end;

End;

Begin

Nhantu;

While sym in ['*','/','%'] do

begin

Trang 14

Pheptinh;

Nhantu; Inc(ip); p[ip]:=i;

end;

End;

Begin

If sym in ['+','-'] then begindaubt:=sym; Pheptinh end Else daubt:='+';

Hangtu;

If daubt='-' then begin i:=Timdau('#');inc(ip); p[ip]:=i; end; While sym in ['+','-'] do

begin

daubt:=sym;

Pheptinh;

Hangtu;

i:=Timdau(daubt); Inc(ip); p[ip]:=i;

end;

End;

ProcedureTinh(i: integer);

Begin

Case p[i] of

-1: beginstack[sst-1]:=stack[sst-1]+stack[sst]; Dec(sst); end; -2: beginstack[sst-1]:=stack[sst-1]-stack[sst]; Dec(sst); end;

Trang 15

-3: beginstack[sst-1]:=stack[sst-1]*stack[sst]; Dec(sst); end; -4: begin stack[sst-1]:=stack[sst-1]div stack[sst]; Dec(sst); end; -5: begin stack[sst-1]:=stack[sst-1]mod stack[sst]; Dec(sst); end; -6: stack[sst]:=-stack[sst];

End;

End;

ProcedureNapso(i: integer);

Begin

Inc(sst);

stack[sst]:=tri[p[i]];

End;

ProcedureHoiso(i: integer);

Var

j: integer;

Begin

Delete(ten[p[i]],1,1);

tri[p[i]]:=0;

For j:=1 to Sobien do

If tenbien[j]=ten[p[i]] then

begin

tri[p[i]]:=Value[j];

break;

end;

Trang 16

End;

ProcedureTinhtoan;

Var

i: integer;

Begin

For i:=1 to ip do

begin

If p[i]<0 then Tinh(i)

Else

Case ten[p[i],1] of

' ': Napso(i);

'?': begin Hoiso(i); Napso(i);end; '&': Napso(i);

End;

end;

End;

ProcedureMain;

Begin

Pheptinh;

Bieuthuc;

Tinhtoan;

End;

Trang 17

Var

i: integer;

Begin

Assign(g,fo); Rewrite(g);

Writeln(g,s,' = ',stack[1]);

Close(g);

End;

BEGIN

Clrscr;

Init;

Main;

Done;

END

Chươngtrình trên chưa hoàn chỉnh, bởi vì nó chưa tính được các giá trị hàm lượnggiác, hàm logarit, v v Nếu muốn có chương trình 4Đ (đầy đủ, đúng đắn!) cácbạn hãy liên hệ với tác giả theo địa chỉ email: chuong@bonbon.net

Ngày đăng: 11/09/2012, 14:59

TỪ KHÓA LIÊN QUAN

w