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

BÁO CÁO BÀI TIỂU LUẬN ĐÊ TÀI NGĂN XẾP,HÀNG ĐỢI TÍNH GIÁ TRỊ BIỂU THỨC THEO PHƯƠNG PHÁP NGHỊCH ĐẢO BA LAN

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 (171.29 KB, 25 trang )

ĐẠI HỌC PHÚ YÊN
KHOA KỸ THUẬT – CÔNG NGHỆ

BÁO CÁO BÀI TIỂU LUẬN
ĐÊ TÀI: NGĂN XẾP,HÀNG ĐỢI
TÍNH GIÁ TRỊ BIỂU THỨC THEO PHƯƠNG PHÁP NGHỊCH ĐẢO
BA LAN
GIÁO VIÊN HƯỚNG DẪN: TRẦN MINH CẢNH
SINH VIÊN THỰC HIỆN : NHÓM 2
LỚP : ĐẠI HỌC SƯ PHẠM TIN HỌC – C13
MÔN HỌC : CẤU TRÚC DỮ LIỆU VÀ THUẬT TOÁN
LỜI MỞ ĐẦU
Cấu trúc dữ liệu và thuật toán là một trong những môn học cơ
bản của sinh viên ngành Công nghệ thông tin. Các cấu trúc dữ liệu và
các giải thuật được xem như là 2 yếu tố quan trọng nhất trong lập
trình, đúng như câu nói nỗi tiếng của Niklaus Wirth: Chương trình=
Cấu trúc dữ liệu + Giải thuật (Programs=Data Structures+
Algorithms). Nắm vững các cấu trúc dữ liệu và các giải thuật là cơ sở
để sinh viên tiếp cận với việc thiết kế và xây dựng phần mềm cũng
như sử dụng các công cụ lập trình hiện đại.
Hai cấu trúc dữ liệu rất gần gũi với các hoạt đọng trong thực tế,
đó là ngăn xếp và hàng đợi.
Ngăn xếp là một dạng đặc biệt của danh sách mà việc bổ sung
hay loại bỏ một phần tử đều được thực hiện ở 1 đầu của danh sách.
Ngăn xếp còn được gọi là kiểu dữ liệu có nguyên tắc LIFO (Last In
First Out- Vào sau ra trước).
Hàng đợi là một cấu trúc dữ liệu gần giống với ngăn xếp, nhưng
phần tử được lấy ra khỏi hàng đợi không phải là phần tử mới nhất
được đưa vào mà là phần tử đã được lưu trong hàng đợi lâu nhất. Quy
luật này được gọi là vào trước ra trước (FIFO- First In First Out).


 Những gì đã đạt được:
-Tìm hiểu được cơ sở lý thuyết của ngăn xếp và hàng đợi.
- Biết được các ứng dụng của ngăn xếp
- Biết cách chuyển đổi biểu thức từ dạng trung tố sang hậu tố.
- Tính được biểu thức theo phương pháp nghịch đảo BaLan.
-Viết được chương trình ngăn xếp và tính biểu thức nghịch đảo
BaLan.
 Những gì chưa đạt được
- Chưa Demo được 2 chương trình đã viết
- Ứng dụng khử đệ quy của ngăn xếp chưa được tìm hiểu kĩ
Mục lục
A.Ngăn xếp và hàng đợi………………………………………2
I.Ngăn xếp……………………………………………………2
1.Khái niệm…………………………………………… 2
2.Tổ chức ngăn xếp bằng mảng 3
3.Các phép toán……………………………………… 4
a.Khởi tạo Stack………………………………… 4
b.Các thao tác chính cho Stack………………… 5
c.Chương trình Demo các thao tác trên Stack……7
4.Tổ chức ngăn xếp bằng danh sách liên kết…………….8
5.Các ứng dụng của ngăn xếp………………………… 12
II.Hàng đợi(Queue) ……………………………………… 13
1.Khái niệm……………………………………………13
2.Tổ chức hàng đợi bằng mảng……………………… 13
3. Các thao tác trên hàng đợi………………………….14
B. Tính giá trị biểu thức theo phương pháp nghịch đảo Ba
Lan …………………………………………………………………16
I. Thuật toán chuyển biểu thức dạng trung tố sang hậu
tố 17
II. Thuật toán tính giá trị biểu thức hậu tố …………… 19

III. Chương trình Demo tính giá trị biểu thức nghịch đảo Ba
Lan …………………………………………………………… 20
A.NGĂN XẾP VÀ HÀNG ĐỢI
I.NGĂN XẾP(Stack)
1.Khái niệm:
Ngăn xếp là một dạng danh sách đặc biệt chỉ thực hiện được hai thao tác:
thêm một phần tử vào cuối danh sách (push) và lấy phần tử cuối ra khỏi danh
sách (pop).
Như vậy trong một ngăn xếp, phần tử vào sau sẽ lấy ra trước nên còn gọi là
danh sách kiểu LIFO (Last in first out).Vị trí của phần tử của phần tử cuối cùng
của ngăn xếp còn gọi là đỉnh(top)của ngăn xếp.
 Các thao tác trên ngăn xếp gồm hai thao thao tác cơ bản là:
• Push(x,S): Đưa phần tử x vào ngăn xếp .
• Pop(x,S): Lấy phần tử ở đỉnh ngăn xếp S ra và lưu vào biến x.
Ngoài ra, còn có các thao tác bổ sung:
a
4
a
3
a
2
a
1
Push
pop
• Init(S):Khởi tạo một ngăn xếp S rỗng.
• Full(S): Cho biết ngăn xếp S có đầy không.
• Clear(S): Làm rỗng ngăn xếp S.
• Gettop(S): Lấy phần tử ở đỉnh ngăn xếp.
• Length(S): Cho biết số phần tử của ngăn xếp.

2) Tổ chức ngăn xếp bằng mảng:
Một ngăn xếp tổ chức bằng mảng bao gồm hai thành phần:
• Một mảng để lưu các phần tử của ngăn xếp.
• Vị trí đỉnh của ngăn xếp.
Hình ảnh ngăn xếp
S=(a
1,
a
2, ……,
a
n
) tổ
chức bằng mảng
như sau:
 Khai báo dữ liệu:
Const
MaxLength = ….; { Số phần tử tối đa của một ngăn xếp}
Type
ElementType = …; {Định nghĩa kiểu phần tử cho ngăn xếp}
StackArr = Record
Element : Array[1 MaxLength] of ElementType;
MaxLength
Top a
n
… …
2 a
2
1 a
1
Top : 0 MaxLength;

End;
Var S: StackArr
3.Các phép toán:
a.Khởi tạo stack:
• Tạo 1 stack S rỗng : Top = 0




• Giá trị của Top sẽ cho biết số phần tử hiện hành có trong stack:
Procedure Init(var S: StackArr);
Begin
S.top := 0;
End;
• Khi cài đặt mảng 1 chiều, stack bị gia hạn bởi kích thước nên cần xây
dựng thêm một thao tác phụ cho stack:
Hàm Full sẽ kiểm tra đỉnh ngăn xếp, nếu Top =MaxLength thì ngăn xếp
đầy.
Function Full ( S: StackArr) : BooLean;
Begin
Full := (S.top = MaxLength);
End;
Hàm Empty sẽ kiểm tra đỉnh ngăn xếp, nếu top=0 thì ngăn xếp rỗng.
Function Empty(S :StackArr): Boolean;
Begin
Empty := (S.top =0);
End;
b.Các thao tác chính cho Stack:
 .Thêm một phần tử x vào đỉnh ngăn xếp S:
Thêm phần tử A vào ngăn xếp Push (S,A)




A
Sau đó sẽ là phần tử B Push (S,B)


B
A
Sau đó sẽ là phần tử C Push (S,C)

C
B
A
Procedure Push(x : ElementType; var S: StackArr);
Begin
If not Full(S) then
With S do
Begin
Inc(top);
Element[top] := x;
End;
 Lấy phần tử cuối từ ngăn xếp S ra khỏi biến x:
Lệnh Pop(S) sẽ lấy phần tử mới được thêm vào ra khỏi Stack, đó là phần
tử C

B
A
Sau đó sẽ là phần tử B


A
Procedure Pop(var x: ElementType; var S : StackArr);
Begin
If not Empty(S) then
With S do
C
C
B
Begin
x:= element[top];
dec(top);
end;
End;
 Nhận xét:
• Các thao tác trên đều làm việc với độ phức tạp 0(1)
• Việc cài đặt Stack thông qua mảng một chiều đơn giản và khá hiệu quả
• Tuy nhiên hạn chế lớn nhất của phương án cài đặt này là giới hạn về
kích thước của Stack:
Là ta cần phải biết trước kích thước tối đa của ngăn xếp (giá trị max trong khai
báo ở trên). Điều này không phải lúc nào cũng xác định được và nếu ta chọn
một giá trị bất kỳ thì có thể dẫn đến lãng phí bộ nhớ nếu kích thước quá thừa so
với yêu cầu hoặc nếu thiếu thì sẽ dẫn tới chương trình có thể không hoạt động .
b. Chương trình Demo các thao tác trên Stack
Program stack_by_array;
Const max =1000;
Var
Stack: Array[1 max] of integer;
Top: integer;
Procedure stack_init;
Begin

Top:=0;
End;
Procedure Push(v: integer);
Begin
If top= Max then writeln (“ngăn xếp đầy”)
Else
Begin
Inc(top); Stack[top]:= v;
End;
End;
Function Pop: integer;
Begin
If top=0 then writeln (“ ngăn xếp rỗng”)
Else
Begin
Pop := stack[top]; Dec(top);
End;
End;
BEGIN
Stack_init;
<test>;
4. Tổ chức ngăn xếp bằng danh sách liên kết:
Để khắc phục nhược điểm của tổ chức ngăn xếp bằng mảng ta có thể sử dụng
danh sách liên kết để cài đặt ngăn xếp.
Để cài đặt ngăn xếp bằng danh sách liên kết, ta sử dụng 1 danh sách liên kết
đơn. Theo tính chất của danh sách liên kết đơn, việc bổ sung và loại bỏ một
phần tử khỏi danh sách được thực hiện đơn giản và nhanh nhất khi phần tử đó
nằm ở đầu danh sách. Do vậy, ta sẽ chọn cách lưu trữ của ngăn xếp theo thứ
tự: phần tử đầu danh sách là đỉnh ngăn xếp, và phần tử cuối cùng của danh
sách là đáy ngăn xếp.

Hình ảnh của ngăn xếp S=(a
1
,a
2
,…,a
n
) tổ chức bằng danh sách liên kết như
sau:
a
1
Để bổ sung 1 phần tử vào danh sách, ta tạo ra 1 nút mới và thêm nó vào đầu
danh sách. Để lấy 1 phần tử khỏi ngăn xếp, ta chỉ cần lấy giá trị nút đầu tiên
và loại nút ra khỏi danh sách.
Đỉnh ngăn xếp Đáy ngăn xếp
 Khai báo
Type
StackLink = ^Cell;
Cell = Record
Data : ElementType;
Link : StackLink;
End;
Var S : StackLink;
 Các thao tác trong tổ chức ngăn xếp bằng danh sách liên kết
• Khởi tạo đỉnh ngăn xếp:
NIL
a
2
a
n
Thao tác này thực hiện việc gán giá trị null cho nút đầu ngăn xếp, cho biết

ngăn xếp đang ở trạng thái rỗng.
TOP
Procedure Init(Var S: StackLink);
Begin
S := Nil;
End;
Hàm Empty : Kiểm tra xem Stack có rỗng không
Funtion Empty (S: StackLink): Boolean;
Begin
Empty := (S=Nil);
End;
 Thêm phần tử x vào đỉnh ngăn xếp S:
S
P
Đỉnh ngăn xếp
S
NIL
NIL
NIL
NIL
Đỉnh mới
 Đoạn chương trình:
Procedure Push (x : ElementType; var S: StackLink);
Var p: StackLink;
Begin
New(p); p^.Data:=x;
P^.Link:=S; S:=p;
End;
• Lấy một phần tử ra khỏi stack:
Đỉnh mới

Procedure Pop(Var x:ElmentType; var S: StackLink);
Var p: StackLink;
Begin
If not Empty (S) then
Begin
x:= S^.Data;
p:= S;
S:= p^.Link;
NIL
Dispose(p);
End;
End;
• Làm rỗng ngăn xếp: xóa và thu hồi các ô nhớ.
Procedure Clear(var S: StackLink);
Var p : StackLink;
Begin
While not Empty(S) do
Begin
P:= S;
S:= p^.Link;
Dispose(p);
End;
End;
5. Các ứng dụng của ngăn xếp:
• Khử đệ quy
• Tính giá trị của các biểu thức
 Nhận xét:
Tổ chức ngăn xếp bằng danh sách liên kết thích hợp lưu trữ các loại dữ liệu
mà trình tự xuất ngược với trình tự lưu trữ.
II)Hàng đợi: (Queue)

1.Khái niệm:
Hàng đợi là một kiểu dữ liệu trừu tượng xây dựng trên mô hình danh sách
với hai thao tác cơ bản:
+Thêm một phần tử vào cuối hàng đợi.
+Lấy phần tử đầu ra khỏi hàng đợi.
Hàng đợi được thực hiện theo nguyên tắc : các phần tử đưa vào trước lấy
ra trước nên còn gọi là danh sách FIFO (Firt in Firt out).
Hàng đợi Q= ( a
1
;a
2
;…;a
n
) được thể hiện bằng hình dưới
Lấy ra thêm vào
2.Tổ chức hàng đợi bằng mảng:
Hàng đợi tổ chức bằng mảng cũng giống như hình danh sách nhưng cần hai
thành phần để lưu vị trí phần tử sẽ được lấy ra ở đầu hàng đợi (front) và vị trí
phần tử thêm vào cuối cùng của hàng đợi (rear).
Front rear
Khai báo dữ liệu :
Const
Maxlength = ……;{số phần tử tối đa của hàng đợi}
Type
ElementType=… ; {định nghĩa phần tử tối cho hàng đợi}
a
1
a
2
… a

n
a
1
a
2
… a
n
Queue = Record
Elemen:Array[1 Maxlength] of ElementType;
Front , Rear:0 Maxlength;
Var Q:Queue;
3.Các thao tác trên hàng đợi:
• Khởi tạo hàng đợi:
Procedure InitQueue(var Q:Queue);
Begin
Q.Front:=1;
Q.Rear:=0;
End;
• Hàm Emply:(kiểm tra hàng đợi rỗng)
Function Emply(Q:Queue):Boolean;
Begin
Emply := (Q.rear = 0);
End;
• Thêm vào một phần tử:
Thêm phần tử x vào hàng đợi Q
Procedure themQueue(x:ElementType;var Q:Queue);
Begin
If not Full(Q) then
Begin
Q.rear := Q.rear +1;

Q.element[Q.rear] : = x;
End;
End;
• Lấy một phần tử ra khỏi hàng đợi Q:
Procedure RemoveQueue(var x:ElementType;var Q:Queue);
Begin
Ì not Emply(Q) then
Begin
X:=Q.elemeny[Q.front];
If Q.front = Q.rear then
Begin Q.front ;==1;Q rear := );end
Else
Q.front := Q.front +1;
End ;
End ;
 Nhận xét :
Với cách tổ chức hàng đợi bằng mảng và các thao tác trên sẽ gặp nhiều hạn
chế .
B. Tính giá trị biểu thức theo phương pháp nghịch đảo BaLan
Khi thực hiện chương trình, các ngôn ngữ lập trình thường phải tính giá
trị của biểu thức. Thông thường, các ngôn ngữ lập trình tính giá trị biểu thức
bằng cách :
+ Chuyển biểu thức từ dạng trung tố(infix) sang dạng hậu tố (posfix).
+ Tính giá trị biểu thức hậu tố.
Biểu thức trung tố là cách con người thường sử dụng, trong biểu thức
trung tố các phép toán hai ngôi được viết giữa hai toán hạng. Việc tính trực
tiếp các biểu thức trung tố gặp khó khăn vì phải dùng các cặp dấu ngoặc đơn
để quy định thứ tự thực hiện các biểu thức con. Để tính các biểu thức, người
BaLan đã đưa ra một ký pháp quy định cách viết các biểu thức( gọi là kí pháp
BaLan) trong đó các phép toán được đặt sau toán hạng. Việc dùng kí pháp

BaLan không cần dấu ngoặc nhưng vẫn thể hiện được thứ tự ưu tiên khi tính
giá trị biểu thức nên dễ dàng xây dựng thuật toán tính.
Ví dụ : Biểu thức dạng trung tố : 3+(5-2)*3/7-4
Chuyển sang dạng hậu tố là : 3 5 2 -3* 7/4 - +
Thuật toán chuyển biểu thức dạng trung tố sang dạng hậu tố :
Giả sử ta có một biểu thức E dạng trung tố trong đó ta có thể phân tích thành
các thành phần của biểu thức là các toán hạng và phép toán.
Dùng một ngăn xếp S mỗi phần tử là phép toán hoặc dấu ngoặc mở. Kết quả
đưa ra biểu thức hậu tố E
1
.
I.Thuật toán chuyển biểu thức dạng trung tố sang hậu tố.
1. Khởi tạo biểu thức E1, rỗng
2. Duyệt lần lượt từ trái sang phải các thành phần cảu biểu thức E1, với
mỗi thành phần x thực hiện :
2.1 Nếu x là toán hạng thì nối vào bên phải biểu thức E1.
2.2 Nếu x là dấu ngoặc mở thì đưa vào ngăn xếp
2.3 Nếu x là phép toán thì :
a. Đọc phần tử y ở đầu ngăn xếp.
b. Nếu độ ưu tiên của y cao hơn hoặc bằng x thì
- Lấy y ra khỏi ngăn xếp
- Nối y vào bên phải E1
- Lặp lại bước a.
c. Nếu độ ưu tiên của x cao hơn y thì đưa x vào ngăn xếp .
d. Nếu ngăn xếp rỗng thì đưa x vào ngăn xếp .
2.4 Nếu x là dấu ngoặc đóng thì :
a. Đọc phần tử y ở đầu ngăn xếp.
b. Nếu y là phép toán thì :
- Lấy y ra khỏi ngăn xếp
- Nối y vào bên phải biểu thức E1

- (2Lặp lại bước a
c. Nếu y là dấu ngoặc mở thì lấy ra khỏi ngăn xếp.
3. Lặp lại bước 2 cho đến hết biểu thức E
4. Lấy lần lượt các phần tử của ngăn xếp và nối vào bên phải biểu thức E1
cho đến khi ngăn xếp rỗng.
Ví dụ : Với biểu thức E=(2+7*3-8)*4-(3+2)*3-2, thuật toán chuyển thành
biểu thức hậu tố thực hiện các bước được thể hiện qua các kết quả ở bảng
sau :
Thành phần của biểu thức E Ngăn xếp Biểu thức E
1
(
2
+2
7
*
3
-
8
)
*
4
-
(
3
+
2
)
*
3
(

(
(+
(+
(+*
(+*
(-
(-

*
*
-
-(
-(
-(+
-(+
-
-*
-*

2
2
2 7
2 7
2 7 3
2 7 3*+
2 7 3*+ 8
2 7 3 *+8-
2 7 3*+ 8-
2 7 3*+ 8-4
2 7 3*+ 8-4*

2 7 3*+ 8-4*
2 7 3*+ 8-4*3
2 7 3*+ 8-4*3
2 7 3*+ 8-4*3 2
2 7 3*+ 8-4*3 2+
2 7 3*+ 8-4*3 2+
2 7 3*+ 8-4*3 2+3
-
2
-
-

2 7 3*+ 8-4*3 2+3*-
2 7 3*+ 8-4*3 2+3*-2
2 7 3*+ 8-4*3 2+3*-2-
II.Thuật toán tính giá trị biểu thức hậu tố
Cho biểu thức viết dưới dạng hậu tố E1. Để tính giá trị của biểu thức ta dùng
một ngăn xếp S lưu các toán hạng và các kết quả tính toán trung gian.
Thuật toán
1. Duyệt lần lượt cac phần tử của biểu thức E1, với thành phần x thực
hiện :
a. Nếu x là toán hạng thì đưa vào ngăn xếp.
b. Nếu x là phép toán thì lấy hai phần tử đầu ngăn thực hiện tính theo
phép toán và đưa kết quả vào ngăn xếp.
2. Lặp lại bước 1 cho đến khi hết biểu thức.
3. Giá trị duy nhất còn lại của ngăn xếp là kết quả của biểu thức E1.
Ví dụ : Kết quả tính biểu thức hậu tố E1= 2 7 3*+8-4*3 2+3*-2- qua các
bước được biểu diễn bởi bảng sau :
Thành phần biểu thức E
1

Ngăn xếp
*2
7
3
*
+
2
2 7
2 7 3
2 21
23
8
-
4
*
3
2
+
3
*
-
2
-
23 8
15
15 4
60
60 3
60 3 2
60 5

60 5 3
60 15
45
45 2
43
III. Chương trình demo tính giá trị biểu thức nghịch đảo BaLan
program tinhgiatribieuthuc;
const
Opt = ['+', '-', '*', '/'];
var
T, RPN: String;
Stack: array[1 255] of Extended;
p, Last: Integer;
procedure StackInit;
begin
Last := 0;
end;
procedure Push(V: Extended);
begin
Inc(Last); Stack[Last] := V;
end;
function Pop: Extended;
begin
Pop := Stack[Last]; Dec(Last);
end;
procedure Refine(var S: String); {Hiệu chỉnh biểu thức RPN về khuôn dạng
dễ đọc nhất}
var
i: Integer;
begin

S := S + ' ';
for i := Length(S) - 1 downto 1 do {Thêm những dấu cách giữa toán hạng và
toán tử}
if (S[i] in Opt) or (S[i + 1] in Opt) then
Insert(' ', S, i + 1);
for i := Length(S) - 1 downto 1 do {Xoá những dấu cách thừa}
if (S[i] = ' ') and (S[i + 1] = ' ') then Delete(S, i + 1, 1);
end;
procedure Process(T: String); {Xử lý phần tử T đọc được từ biểu thức RPN}
var
x, y: Extended;
e: Integer;
begin
if not (T[1] in Opt) then {T là toán hạng}
begin
Val(T, x, e); Push(x); {Đổi T thành số và đẩy giá trị đó vào Stack}
end
else {T là toán tử}
begin
y := Pop; x := Pop; {Ra hai}
case T[1] of
'+': x := x + y;
'-': x := x - y;
'*': x := x * y;
'/': x := x / y;
end;
Push(x); {Vào một}
end;
end;
begin

Write('Enter RPN Expression: '); ReadLn(RPN);
Refine(RPN);
StackInit;
T := '';
for p := 1 to Length(RPN) do {Xét các ký tự của biểu thức RPN từ trái qua
phải}
if RPN[p] <> ' ' then T := T + RPN[p] {nếu không phải dấu cách thì nối nó
vào sau xâu T}
else {Nếu gặp dấu cách}
begin
Process(T); {Xử lý phần tử vừa đọc xong}
T := ''; {Đặt lại T để chuẩn bị đọc phần tử mới}
end;
WriteLn(RPN, ' = ', Pop:0:4); {In giá trị biểu thức RPN được lưu trong Stack}
end.

DANH SÁCH NHÓM 2
1. TRẦN THỊ MY LY
2. NGUYỄN HOÀI THƯƠNG

×