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

Cây biểu thức số học

13 2,1K 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

Tiêu đề Cây biểu thức số học
Tác giả Nguyễn Tuấn Dũng
Trường học Trường Đại Học Khoa Học Tự Nhiên
Thể loại bài viết
Năm xuất bản 2002
Thành phố Hồ Chí Minh
Định dạng
Số trang 13
Dung lượng 150,5 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Cây biểu thức số học

Trang 1

Cây biểu thức số học

Nguyễn Tuấn Dũng

Chúng ta đã có bài ″Xử lý biểu thức số học″ của bạn Lê Văn Chương trong THNT số 29 (tháng 2/2002) Tác giả trình bày phương pháp tính biểu thức số học theo cách đưa về dạng

ký pháp nghịch đảo Balan và sử dụng cấu trúc dữ liệu kiểu stack (ngăn xếp) Trong bài viết này, tôi muốn bàn về một phương pháp khác khá thuận tiện cho việc biểu diễn và tính toán

biểu thức số học, đó là cây biểu thức số học Để đơn giản và nhằm mục đích làm nổi bật

những đặc trưng của phương pháp này, chúng ta giói hạn xâu biểu thức nhập vào chỉ ở mức độ sau:

- Các số hạng chỉ là một kí tự (′0′ ′9′) hoặc ′A′ ′z′)

Các phép toán bao gồm 4 phép toán hai ngôi : +,-,*,/

Ngoài ra, các dấu ngoặc có thể có hoặc không và giả sử biểu thức nhập vào đã đúng quy cách (bạn có thể xem lại thủ tục kiểm tra biểu thức nhập vào đã đúng quy cách hay chưa trên THNT số 29)

Biểu diễn cây nhị phân bằng cấu trúc dữ liệu kiểu con trỏ

Xuất phát từ đặc điểm các phép toán của chúng ta chỉ là các phép toán hai ngôi nên cách

mô tả phù hợp và tiện lợi nhất cho biểu thức số học chính là một cây nhị phân đầy đủ (số nút trên các mức đều là tối đa)

Trong đó, các phép toán +,-,*,/ sẽ nằm tại các gốc (có cây con), còn các số hạng thì nằm trên lá (các nút tận cùng của cây, không có cây con) Bên trái của mỗi gốc là cây con trái

biểu diễn cho biểu thức bên trái phép toán nằm tại gốc đó và tương tự như thế, bên phải là

cây con phải biểu diễn cho biểu thức bên phải của phép toán Phép toán được thực hiện cuối cùng trong biểu thức sẽ nằm tại gốc chính của cây Có thể lấy ví dụ về hình ảnh một

cây biểu thức như hình vẽ bên

Để biểu diễn một cây nhị phân, ta dùng kiểu dữ liệu con trỏ Định nghĩa như sau:

Type ptr=^node;

Node=record

Info: char;

l,r: ptr;

End;

Var T:ptr;

Trong đó T^.info chứa thông tin tại gốc cây, T^.l chứa địa chỉ trỏ tới cây con trái của T, T^.r chứa địa chỉ trỏ tới cây con phải của T Và tiếp tục T^.l^.info sẽ chứa thông tin tại gốc cây con trái, T^.l^.l chứa địa chỉ trỏ tới cây con trái của cây con trái của T, T^.l^.r chứa địa chỉ trỏ tới cây con phải của cây con trái của T

Thuật toán chuyển biểu thức trung tố thành một cây biểu thức

Tiếp theo, giả sử biểu thức ban đầu được nhập vào dưới dạng một xâu kí tự (giống như ví dụ: s=′(a-b)*(c-d)′ ) Dùng mảng A một chiều, mỗi phần tử của mảng là một bản ghi gồm

hai trường : info và ut , ta sẽ có thuật toán chuyển biểu thức dạng trung tố này thành một

cây biểu thức như sau :

Trang 2

1 Khởi tạo:

-Thiết lập độ ưu tiên cho các phép toán: utcongtru:=1;

utnhanchia:=2;

- Dùng một biến uutien để lưu mức độ ưu tiên hiện thời (ban đầu khởi tạo bằng 0)

2 Duyệt biểu thức trung tố từ trái qua phải:

- Gặp ′(′ thì inc(uutien,2), gặp ′)′ thì dec(uutien,2) Chú ý: không đưa dấu ngoặc vào mảng A.

- Gặp số hạng thì đưa vào A như sau: A[i].info:=số hạng;

A[i].ut:=10000;

{có thể gán bằng một hằng tuỳ ý nhưng phải tương đối lớn, như maxint chẳng hạn (điều

này sẽ được sử dụng trong bước 3)}

- Gặp phép toán +,- [hoặc *,/] thì đưa vào A như sau:

A[i].info:=phép toán;

A[i].ut:= utcongtru[hay utnhanchia] + uutien.

Ví dụ, biểu thức ban đầu là: (a+b*(c-d) thì ta được mảng A như sau :

3 Đệ quy:

- Trong mảng A, tìm bản ghi phải nhất và có độ ưu tiên bé nhất lấy làm gốc cây Toàn bộ phần mảng A bên trái bản ghi này sẽ tương ứng với biểu thức bên trái và là cây con trái Còn phần mảng A bên phải bản ghi này tương ứng với biểu thức bên phải và là cây con phải

- Hai cây con này tính chất và đặc điểm cũng giống như cây ban đầu Vì thế ta lại tiếp tục tìm bản ghi phải nhất và có độ ưu tiên bé nhất của 2 biểu thức bên trái và bên phải này để làm gốc của các cây con trái và cây con phải tương ứng ở mức thấp hơn (xem thêm

chương trình ở dưới)

- Quá trình đệ quy sẽ được dừng khi biểu thức của chúng ta chỉ gồm một phần tử của mảng

A, đó chính là các số hạng ứng với các nút lá của cây biểu thức

Để minh hoạ cho bước 3, ta sẽ thực hiện với ví dụ trên (hình vẽ có trong file attachment): + Từ phần tử đầu đến phần tử cuối của mảng A, tìm bản ghi phải nhất và có độ ưu tiên bé nhất: A[4] => cây hiện thời (hình 1):

+Từ A[1] đến A[3], bản ghi phải nhất và có độ ưu tiên bé nhất: A[2] => cây hiện thời (hình 2):

+ Từ A[1] đến A[1], bản ghi cần tìm: A[1] => cây hiện thời (hình 3)

+ Từ A[3] đến A[3], bản ghi cần tìm: A[3] => cây hiện thời (hình 4)

+ Từ A[5] đến A[7] bản ghi phải nhất và có độ ưu tiên bé nhất: A[6] => cây hiện thời (hình 5):

+Từ A[6] đến A[6], bản ghi cần tìm: A[6] => cây hiện thời (hình 6)

+Từ A[7] đến A[7], bản ghi cần tìm: A[7] => cây hiện thời (hình7)

Trang 3

4 Thủ tục đệ quy tính giá trị cây biểu thức

Một cách trực quan mà nói thì ta có thể thấy ngay việc sử dụng giải thuật đệ quy để tính giá trị cây biểu thức là đơn giản và thích hợp nhất Khi duyệt đến từng nút của cây, nếu là một trong bốn phép toán +,-,*,/ thì giá trị của cây sẽ được tính bằng giá trị của cây con trái cộng, trừ, nhân, hoặc chia tương ứng cho giá trị cây con phải (giá trị của hai cây con này lại được tính tiếp nhờ lệnh gọi đệ quy) Còn nếu nút đó là một số hạng thì giá trị của cây

được gán bằng giá trị số hạng đó và dừng lại, không gọi đệ quy nữa (xem Procedure DuyetTruoc;) Duyệt cây theo kiểu này được gọi là duyệt cây theo thứ tự trước (thăm gốc,

rồi lần lượt duyệt cây con trái và cây con phải theo thứ tự trước) và ta sẽ được biểu thức tiền tố Còn nếu duyệt theo thứ tự giữa (duyệt cây con trái theo thứ tự giữa, thăm gốc, rồi duyệt cây con phải theo thứ tự giữa) hay duyệt theo thứ tự sau (duyệt cây con trái theo thứ

tự sau, duyệt cây con phải theo thứ tự sau rồi mới thăm gốc) ta sẽ được tương ứng biểu thức trung tố và biểu thức hậu tố (hay kiểu kí pháp nghịch đảo Ba Lan) Do đó, tương tự

như vậy có thể thay thủ tục DuyetTruoc; bằng 2 thủ tục Duyetgiua; và Duyetsau; (ở cuối chương trình )

Dưới đây là chương trình tính biểu thức theo thuật toán trên Xin dành việc update phần xử

lý xâu kí tự cho bạn đọc để có được một chương trình toàn vẹn hơn

Trang 4

uses crt;

type ptr=^node;

node = record

info : char;

l,r : ptr;

end;

bg = record

info : char;

ut : integer;

end;

const maxbg = 256;

var s : string;

a : array[1 maxbg]of bg;

sbg:integer; Tree:ptr; result:real;

procedure Bt_to_bg;

{Từ biểu thức nhập vào xây dựng nên mảng các bản ghi}

ar i,j,k,uutien:integer;

begin

Write('Ban can tinh bieu thuc : '); readln(s);

uutien:=0; sbg:=0;

for i:=1 to length(s) do

begin

inc(sbg);

a[sbg].info:=s[i];

case s[i] of

'(' : begin

inc(uutien,2);

dec(sbg);

end;

')' : begin

dec(uutien,2);

dec(sbg);

end;

'0' '9','A' 'z' : a[sbg].ut:=10000;

'+','-' : a[sbg].ut:=1 + uutien;

'*','/' : a[sbg].ut:=2 + uutien;

end;

end;

end;

function Right_min_bg(d,c:integer):integer ;

{Tim vi tri phai nhat co uu tien min trong a}

var i,j,k:integer;

begin

k:=10000;

for i:=c downto d do

begin

Trang 5

if a[i].ut

begin

k:=a[i].ut;

j:=i;

end;

end;

Right_min_bg:=j;

end;

function Bg_to_Tree(d,c:integer):ptr;

{Xây dựng cây biểu thức từ mảng các bản ghi}

var i,j,k:integer; p:ptr;

begin

new(p);

i:=Right_min_bg(d,c);

with P^ do

begin

if d

begin

info:=a[i].info;

l:=Bg_to_Tree(d,i-1);

r:=Bg_to_Tree(i+1,c);

end

else

begin

info:=a[d].info;

l:=nil;

r:=nil;

end;

end;

Bg_to_Tree:=P;

end;

function DuyetTruoc(T:ptr):real;

{Duyệt cây theo thứ tự trước để tính giá trị của biểu thức theo kiểu tiền tố} var val:real;

begin

with T^ do

begin

case info of

'0' '9' : val:=ord(info)-ord('0');

'A' 'z' : begin

write('Nhap gia tri cho ',info,'=');

readln(val);

end;

'+' : val:=DuyetTruoc(l)+DuyetTruoc(r);

Trang 6

'-' : val:=DuyetTruoc(l)-DuyetTruoc(r);

'*' : val:=DuyetTruoc(l)*DuyetTruoc(r);

'/' : val:=DuyetTruoc(l)/DuyetTruoc(r);

end;

end;

DuyetTruoc:=val;

end;

BEGIN

Bt_to_bg;

Tree:=Bg_to_Tree(1,sbg);

Result:=DuyetTruoc(Tree);

Writeln('Gia tri cua bieu thuc la : ',Result:10:3);

readln;

END

function DuyetgiuăT:ptr):real;

{Duyệt cây theo thứ tự giữa để tính giá trị của biểu thức theo kiểu trung tố } var val:real;

begin

with T^ do

begin

if l<>nil then val:=Duyetgiuăl);

case info of

'0' '9' : val:=ord(info)-ord('0');

'A' 'z' : begin

write('Nhap gia tri cho ',info,'=');

readln(val);

end;

'+' : val:=val+Duyetgiuăr);

'-' : val:=val-Duyetgiuăr);

'*' : val:=val*Duyetgiuăr);

'/' : val:=val/Duyetgiuăr);

end;

end;

Duyetgiua:=val;

end;

function Duyetsau(T:ptr):real;

{Duyệt cây theo thứ tự sau để tính giá trị của biểu thức theo kiểu hậutố } var val1,val2,val:real;

begin

with T^ do

begin

if l<>nil then val1:=Duyetsau(l);

if r<>nil then val2:=Duyetsau(r);

case info of

'0' '9' : val:=ord(info)-ord('0');

'A' 'z' : begin

Trang 7

write('Nhap gia tri cho ',info,'=');

readln(val);

end;

'+' : val:=val1+val2;

'-' : val:=val1-val2;

'*' : val:=val1*val2;

'/' : val:=val1/val2;

end;

end;

Duyetsau:=val;

end;

Cây biểu thức số học

Nguyễn Tuấn Dũng

Chúng ta đã có bài ″Xử lý biểu thức số học″ của bạn Lê Văn Chương trong THNT số 29 (tháng 2/2002) Tác giả trình bày phương pháp tính biểu thức số học theo cách đưa về dạng

ký pháp nghịch đảo Balan và sử dụng cấu trúc dữ liệu kiểu stack (ngăn xếp) Trong bài viết này, tôi muốn bàn về một phương pháp khác khá thuận tiện cho việc biểu diễn và tính toán

biểu thức số học, đó là cây biểu thức số học Để đơn giản và nhằm mục đích làm nổi bật

những đặc trưng của phương pháp này, chúng ta giói hạn xâu biểu thức nhập vào chỉ ở mức độ sau:

- Các số hạng chỉ là một kí tự (′0′ ′9′) hoặc ′A′ ′z′)

Các phép toán bao gồm 4 phép toán hai ngôi : +,-,*,/

Ngoài ra, các dấu ngoặc có thể có hoặc không và giả sử biểu thức nhập vào đã đúng quy cách (bạn có thể xem lại thủ tục kiểm tra biểu thức nhập vào đã đúng quy cách hay chưa trên THNT số 29)

Biểu diễn cây nhị phân bằng cấu trúc dữ liệu kiểu con trỏ

Xuất phát từ đặc điểm các phép toán của chúng ta chỉ là các phép toán hai ngôi nên cách

mô tả phù hợp và tiện lợi nhất cho biểu thức số học chính là một cây nhị phân đầy đủ (số nút trên các mức đều là tối đa)

Trong đó, các phép toán +,-,*,/ sẽ nằm tại các gốc (có cây con), còn các số hạng thì nằm trên lá (các nút tận cùng của cây, không có cây con) Bên trái của mỗi gốc là cây con trái

biểu diễn cho biểu thức bên trái phép toán nằm tại gốc đó và tương tự như thế, bên phải là

cây con phải biểu diễn cho biểu thức bên phải của phép toán Phép toán được thực hiện cuối cùng trong biểu thức sẽ nằm tại gốc chính của cây Có thể lấy ví dụ về hình ảnh một

cây biểu thức như hình vẽ bên

Để biểu diễn một cây nhị phân, ta dùng kiểu dữ liệu con trỏ Định nghĩa như sau:

Type ptr=^node;

Node=record

Info: char;

l,r: ptr;

Trang 8

Var T:ptr;

Trong đó T^.info chứa thông tin tại gốc cây, T^.l chứa địa chỉ trỏ tới cây con trái của T, T^.r chứa địa chỉ trỏ tới cây con phải của T Và tiếp tục T^.l^.info sẽ chứa thông tin tại gốc cây con trái, T^.l^.l chứa địa chỉ trỏ tới cây con trái của cây con trái của T, T^.l^.r chứa địa chỉ trỏ tới cây con phải của cây con trái của T

Thuật toán chuyển biểu thức trung tố thành một cây biểu thức

Tiếp theo, giả sử biểu thức ban đầu được nhập vào dưới dạng một xâu kí tự (giống như ví dụ: s=′(a-b)*(c-d)′ ) Dùng mảng A một chiều, mỗi phần tử của mảng là một bản ghi gồm

hai trường : info và ut , ta sẽ có thuật toán chuyển biểu thức dạng trung tố này thành một

cây biểu thức như sau :

1 Khởi tạo:

-Thiết lập độ ưu tiên cho các phép toán: utcongtru:=1;

utnhanchia:=2;

- Dùng một biến uutien để lưu mức độ ưu tiên hiện thời (ban đầu khởi tạo bằng 0)

2 Duyệt biểu thức trung tố từ trái qua phải:

- Gặp ′(′ thì inc(uutien,2), gặp ′)′ thì dec(uutien,2) Chú ý: không đưa dấu ngoặc vào mảng A.

- Gặp số hạng thì đưa vào A như sau: A[i].info:=số hạng;

A[i].ut:=10000;

{có thể gán bằng một hằng tuỳ ý nhưng phải tương đối lớn, như maxint chẳng hạn (điều

này sẽ được sử dụng trong bước 3)}

- Gặp phép toán +,- [hoặc *,/] thì đưa vào A như sau:

A[i].info:=phép toán;

A[i].ut:= utcongtru[hay utnhanchia] + uutien.

Ví dụ, biểu thức ban đầu là: (a+b*(c-d) thì ta được mảng A như sau :

3 Đệ quy:

- Trong mảng A, tìm bản ghi phải nhất và có độ ưu tiên bé nhất lấy làm gốc cây Toàn bộ phần mảng A bên trái bản ghi này sẽ tương ứng với biểu thức bên trái và là cây con trái Còn phần mảng A bên phải bản ghi này tương ứng với biểu thức bên phải và là cây con phải

- Hai cây con này tính chất và đặc điểm cũng giống như cây ban đầu Vì thế ta lại tiếp tục tìm bản ghi phải nhất và có độ ưu tiên bé nhất của 2 biểu thức bên trái và bên phải này để làm gốc của các cây con trái và cây con phải tương ứng ở mức thấp hơn (xem thêm

chương trình ở dưới)

- Quá trình đệ quy sẽ được dừng khi biểu thức của chúng ta chỉ gồm một phần tử của mảng

A, đó chính là các số hạng ứng với các nút lá của cây biểu thức

Để minh hoạ cho bước 3, ta sẽ thực hiện với ví dụ trên (hình vẽ có trong file attachment): + Từ phần tử đầu đến phần tử cuối của mảng A, tìm bản ghi phải nhất và có độ ưu tiên bé nhất: A[4] => cây hiện thời (hình 1):

Trang 9

+Từ A[1] đến A[3], bản ghi phải nhất và có độ ưu tiên bé nhất: A[2] => cây hiện thời (hình 2):

+ Từ A[1] đến A[1], bản ghi cần tìm: A[1] => cây hiện thời (hình 3)

+ Từ A[3] đến A[3], bản ghi cần tìm: A[3] => cây hiện thời (hình 4)

+ Từ A[5] đến A[7] bản ghi phải nhất và có độ ưu tiên bé nhất: A[6] => cây hiện thời (hình 5):

+Từ A[6] đến A[6], bản ghi cần tìm: A[6] => cây hiện thời (hình 6)

+Từ A[7] đến A[7], bản ghi cần tìm: A[7] => cây hiện thời (hình7)

4 Thủ tục đệ quy tính giá trị cây biểu thức

Một cách trực quan mà nói thì ta có thể thấy ngay việc sử dụng giải thuật đệ quy để tính giá trị cây biểu thức là đơn giản và thích hợp nhất Khi duyệt đến từng nút của cây, nếu là một trong bốn phép toán +,-,*,/ thì giá trị của cây sẽ được tính bằng giá trị của cây con trái cộng, trừ, nhân, hoặc chia tương ứng cho giá trị cây con phải (giá trị của hai cây con này lại được tính tiếp nhờ lệnh gọi đệ quy) Còn nếu nút đó là một số hạng thì giá trị của cây

được gán bằng giá trị số hạng đó và dừng lại, không gọi đệ quy nữa (xem Procedure DuyetTruoc;) Duyệt cây theo kiểu này được gọi là duyệt cây theo thứ tự trước (thăm gốc,

rồi lần lượt duyệt cây con trái và cây con phải theo thứ tự trước) và ta sẽ được biểu thức

Trang 10

tiền tố Còn nếu duyệt theo thứ tự giữa (duyệt cây con trái theo thứ tự giữa, thăm gốc, rồi duyệt cây con phải theo thứ tự giữa) hay duyệt theo thứ tự sau (duyệt cây con trái theo thứ

tự sau, duyệt cây con phải theo thứ tự sau rồi mới thăm gốc) ta sẽ được tương ứng biểu thức trung tố và biểu thức hậu tố (hay kiểu kí pháp nghịch đảo Ba Lan) Do đó, tương tự

như vậy có thể thay thủ tục DuyetTruoc; bằng 2 thủ tục Duyetgiua; và Duyetsau; (ở cuối chương trình )

Dưới đây là chương trình tính biểu thức theo thuật toán trên Xin dành việc update phần xử

lý xâu kí tự cho bạn đọc để có được một chương trình toàn vẹn hơn

uses crt;

type ptr=^node;

node = record

info : char;

l,r : ptr;

end;

bg = record

info : char;

ut : integer;

end;

const maxbg = 256;

var s : string;

a : array[1 maxbg]of bg;

sbg:integer; Tree:ptr; result:real;

procedure Bt_to_bg;

{Từ biểu thức nhập vào xây dựng nên mảng các bản ghi}

ar i,j,k,uutien:integer;

begin

Write('Ban can tinh bieu thuc : '); readln(s);

uutien:=0; sbg:=0;

for i:=1 to length(s) do

begin

inc(sbg);

a[sbg].info:=s[i];

case s[i] of

'(' : begin

inc(uutien,2);

dec(sbg);

end;

')' : begin

dec(uutien,2);

dec(sbg);

end;

'0' '9','A' 'z' : a[sbg].ut:=10000;

'+','-' : a[sbg].ut:=1 + uutien;

'*','/' : a[sbg].ut:=2 + uutien;

end;

end;

Ngày đăng: 07/09/2012, 11:39

TỪ KHÓA LIÊN QUAN

w