You are on page 1of 45

DTT 

SSTTAACCKK AAD Trang 1  

TRƯỜ
ỜNG ĐẠI HỌC
C BÁCH
H KHOA
A HÀ NỘI
N
KHOA
A CÔNG NGHỆ THÔNG
T TIN

B TẬP
BÀI T LỚ
ỚN CT
TDL VÀ GIẢ
ẢI THU
UẬT
Ch
hủ đề: STACK
S K ADT

Thành viên:
1. Tô
ô Trọng Hiến (nhómm trưởng)
2. Nguyễn
N Đìnnh Minh
3. Ph
han Huy Tùng
T
4. Nguyễn
N Việệt Phương
5. Trrần Thanh Tùng

Giáo viên
v hướn
ng dẫn: Ngguyễn Đứ
ức Nghĩa

Hà Nội Ngày 20/12/20007

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
 
DTT 
SSTTAACCKK AAD Trang 2   

Mục lục
 

1 Giới thiệu trương trình ...................................................................................... 1


1.1 Định nghĩa ADT(Abstract Data Type) ........................................................ 2
1.2 Định nghĩa Stack và các phép toán cơ bản ................................................... 5
1.3 Đối tượng cất giữ .......................................................................................... 7
1.3.1 Stack dùng mảng ....................................................................................... 7
1.3.2 Mở rộng stack dùng mảng ......................................................................... 9
1.3.3 Stack dùng DSLK .................................................................................... 10
1.4 Các ứng dụng của Stack ............................................................................. 13

2 Cài đặt (trên C). ............................................................................................... 13

2.1 Mô phỏng hoạt động của stack ................................................................... 13

2.2 Bài toán chuyển đổi giữa các cơ số ............................................................ 15

2.3 Polish Problem ( bài toán Balan) ............................................................... 20


2.3.1 Cơ sở lý thuyết......................................................................................... 20
2.3.2 Biểu thức hậu tố và tiền tố ....................................................................... 21
2.3.3 Tính giá trị biểu thức hậu tố .................................................................... 22
2.3.4 Giải thuật tính BTHT............................................................................... 22
2.3.5 Chuyển đổi trung tố sang hậu tố .............................................................. 24
2.3.6 Giải thuật chuyển BTTT sang dạng hậu tố ............................................. 25
2.3.7 Cài đặt giải thuật ...................................................................................... 25

2.4 Một số bài toán khử đệ quy (Derecursion ) ............................................... 32


2.5 Đóng gói stack bằng lớp(Class) trong C++. ............................................... 36

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
 
DTT 
SSTTAACCKK AAD Trang 3   

3 Ứng dụng ........................................................................................................... 37


3.1 Phát bểu bài toán ứng dụng ...................................................................... 37

3.2 Mô tả, đánh giá độ phức tạp của giải thuật .............................................. 39

3.3 Mô tả cài đặt trương trình ......................................................................... 40


3.4 các ví dụ ................................................................................................................................. 41
4 Kết luận .............................................................................................................. 45

1. Giới thiệu trương trình:

Tất cả các phần thầy giáo yêu cầu chúng em xin được trình bày chi tiết để cho tất
cả các bạn không làm về phần này nếu đọc thì đều có thể hiểu được. Bài Tập Lớn
(BTL) được chia làm 3 phần:

Phần 1 giới thiệu về kiểu dữ liệu trừu tượng - Abstract Data Type(ADT); định
nghĩa về ADT Stack cùng với đối tượng cất giữ, các phép toán cơ bản, và một số
ứng dụng của stacks trong thực tế.

Phần 2 nêu các thao tác cài đặt stack như dùng mảng, dùng danh sách liên kết.
phần này có kèm theo các ví dụ minh họa như: dùng stack để chuyển đổi cơ số;
dùng stack để chuyển đổi từ dạng biểu thức trung tố sang hậu tố, và tính biểu thức
hậu tố. Hay có thể dùng cấu trúc stack để khử các bài toán đệ quy với mục đích tối
ưu hóa trương trình. Trong mục cuối phần 2 có phần mở rộng cài đặt stack trên
C++ bằng cách đóng gói các dữ liệu và phương thức của stack vào một lớp có tên
là CStack và thao tác trên lớp này.( tất cả các mục đều có ví dụ hoàn chỉnh).

Phần 3 giới thiệu hai trương trình khá công phu có ứng dụng tất cả các kiến thức
nêu trên(lập trình trên C++ 3.0). Trương trình lớn nhất là Calculator mô phỏng
máy tính điện tử “CASIO fx 570 Nature Display” với giao diện đồ họa kết hợp sử
dụng đồng thời cả chuột và bàn phím(~180KB). Trương trình thứ hai Derivation
tính đạo hàm của một hàm số Y=F(X) bất kì(~40KB). Một trương trình lớn thường
kết hợp nhiều kiểu cấu trúc dữ liệu(CTDL); để trương trình lớn được đầy đủ chúng
em đã nghiên cứu thêm một số CTDL khác như danh sách liên kết (DSLK) kép
(Double Linked List), hay cây nhị phân (Binary Tree) . Trương trình Calculator sử

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
 
DTT 
SSTTAACCKK AAD Trang 4   

dụng DSLK kép để lưu kết quả của các phép tính trước, và trương trình Derivation
sử dụng CDTL kiểu cây để lưu kết quả của phép tính đạo hàm…. Phần lõi của
Calculator là các hàm tính biểu thức áp dụng thuật toán Balan(ứng dụng stack);
còn phần lõi của Dirivation là thao tác trên cây như có vận dụng CTDL stack trong
việt chuyển biểu thưc sang dạng cây để lưu trữ.

Cả hai bài toán trên lấy ý tưởng trong cuốn Cấu Trúc Dữ Liệu Và Giải Thuật của
thầy Đỗ Xuân Lôi.
“Nhóm tác giả xin cam đoan tất cả mọi cài đặt nêu ra là do dầy công suy nghĩ chứ
không phải copy hay trích dẫn từ bất kì nguồn tài liệu nào”.
 

1.1 Định nghĩa ADT(Abstract Data Type)

Dữ liệu từ trước đến nay chúng ta xem sét đều rất cụ thể; ví dụ như kiểu dữ
liệu(KDL) Boolean là một tập hợp hai giá trị TRUE và FALSE và các phép toán
trên nó như là OR, AND, NOT… Do đó ta có thể định nghĩa KDL là một tập hợp
các giá trị và một tập hợp các phép toán trên tập giá trị đó. Có hai loại KDL: KDL
sơ cấp và KDL có cấu trúc hay còn gọi là cấu trúc dữ liệu. KDL sơ cấp như
Boolean, Integer, Bouble… KDL có cấu trúc như SET, ARRAY, STRUCT…
Khác với các kiểu dữ liệu cụ thể trên, Một kiểu dữ liệu trừu tượng(ADT) là một mô
hình toán học cùng với một tập hợp các phép toán (operator) trừu tượng được định
nghĩa trên mô hình đó. Ví dụ tập hợp số nguyên cùng với các phép toán hợp, giao,
hiệu là một kiểu dữ liệu trừu tượng.

ADT là sự tổng quát hóa từ các kiểu dữ liệu nguyên thủy. ta có thể phân biệt ADT
với CTDL bằng một so sánh sau: các CTDL đã được xây dựng thì thường cho một
ngôn ngữ nào đó, chẳng hạn như Pascal hay C…việc chuyển đổi từ một CTDL từ
một ngôn ngữ này sang một ngôn ngữ khác là khá vất vả lại ít mang giá trị kinh tế.
Do đó người ta đã nghĩ ra một phương pháp là trừu tượng hóa dữ liệu cũng như
trương trình để tương thích với gần như tất cả các ngôn ngữ, tiện lợi cho việc cài
đặt vào bất cứ một ngôn ngữ lập trình nào. Do đó trương trình viết cho ADT được
viết bằng giả ngôn ngữ.

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
 
DTT 
SSTTAACCKK AAD Trang 5  

Tác dụnng của trìu tượng hóaa là làm choo trương trrình trở nênn đơn giảnn hơn, sángg sủa
hơn và dễd hiểu hơ ơn. Cụ thể nó c chi tiết và làm nổổi bật lên cáái tông thể nên
n che đi các
rất tiện lợi khi ta muốn
m cài đặt
đ một giảải thuật choo một ngônn ngữ bậc cao.
c Khi càài
đặt mộtt kiểu dữ liệu trừu tượ ợng trên một
m ngôn nggữ lập trìnhh cụ thể, chhúng ta phhải
thực hiệện hai nhiệệm vụ:
1. Biểu
B diễn kiểu
k dữ liệệu trừu tượợng bằng một
m cấu trúúc dữ liệu hoặc một kiểu
d liệu trừ
dữ ừu tượng khhác đã đượ ợc cài đặt.
2. Viết
V các ch hương trìnhh con thực hiện các phép
p toán trên
t kiểu dữ
d liệu trừuu
t
tượng mà ta
t thường gọi
g là cài đặt
đ các phéép toán.
Ở những ngôn ngữ ữ lập trình hướng đốii tượng như C++ hayy Java việcc ứng dụngg
ADT là rất rõ rệt. Ở đó ADT T được đónng gói thànnh các trươ
ơng trình coon, các lớpp
hay tổngg quát hơn n là các đốii tượng, nhhờ đó việc thao
t trên các
c ADT đư ược đơn giiản
đi rất nhhiều. Nó đeem lại cho các trươngg trình một khả năngg mở rộng rất r lớn.
Sau đâyy ta tập chu ung đi sâu vào Stack ADT.

1.2 Định ngh


hĩa Stack
k và các phép
p toán
n cơ
b
bản

1. Địnnh nghĩa ng găn xếp (staack)


Ngăn xếếp (Stack) là một dannh sách tuyyến tính màà phép
bổ xungg và loại bỏ
ỏ phần tử luôn đượcc thực hiện ở
đỉnh (Toop) của nó
ó.

Ta có thhể xem hìn


nh ảnh trựcc quan của ngăn xếp bằng b một chồng
c đ trên bàn.
đĩa đặt
Muốn thhêm vào ch hồng đó 1 đĩa ta để đĩa
đ mới trênn đỉnh Hình 1: cơ cấ
ấu ngăn xếp

chồng, muốn
m lấy các
c đĩa ra khỏi
k chồngg ta cũng phải
p lấy
hư vậy ngănn xếp là mộột cấu trúcc có tính chhất “vào saau Æ ra trư
đĩa trên trước. Nh ước”
và “vàoo trướcÆ raa sau“ (LIFFO (last inn - first outt ). (hình 1)

2. Các phép toán cơ bản trêên ngăn xếpp

Nhưư đã định nghĩa


n một ADT
A đượcc định nghĩĩa bởi các phép
p toán thao
t tác trêên
nó. Ta có
c thể xemm một Stackk ADT bởii các phép toán sau: 

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
 
DTT 
SSTTAACCKK AAD Trang 6   

• MakeNull (S): tạo ra một stack rỗng


mới.
• Top(S): trả về phần tử tại đỉnh stack.
Nếu ngăn xếp rỗng hàm không xác định.
• Push(S,x): thêm một phần tử x vào đỉnh
stack.
• Pop(S): lọai bỏ phần tử ở đỉnh stack. Hình 2: Bài toán tháp cờ Hà Nội

• IsEmpty(S): kiểm tra stack có rỗng hay


không? Hàm cho kết quả 1 nếu rỗng, còn 0 nếu ngược lại.
Các thao tác trên không phụ thuộc vào cách lưu trữ stack bằng mảng hay bằng
DSLK. Với 5 phép toán trên ta đã xây dựng nên một mô hình toán học gọi là một
kiểu dữ liệu trừu tượng stack. Ta sẽ thao tác với ADT này qua môt ví dụ nhỏ.

Ví dụ: Viết chương trình con Reverse_String nhận một chuỗi kí tự từ bàn phím cho
đến khi gặp kí tự # thì kết thúc việc nhập và in kết quả theo thứ tự ngược lại.
void Reverse_String ()
{
Stack S;
char c;
MakeNull(S); // Tạo một stack rỗng
Do
{
c=getche();
Push(S,c); // Lưu từng ký tự vào ngăn
xếp
}while (c!='#');
printf("\nChuoi theo thu tu nguoc lai\n");
while (!IsEmpty(S)) // Khi stack không rỗng
{
printf("%c\n",Top(S)); // Lấy phần tử ở đỉnh stack
Pop(S); // lọai bỏ một phần tử ở đỉnh
stack
}
}

Trương trình trên tuy nhỏ nhưng đã sử dụng tất cả các phép toán cơ bản về stack.
Như đã nói từ trước, khi thiết kế giải thuật ta có thể dùng các phép toán trừu tượng

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
 
DTT 
SSTTAACCKK AAD Trang 7  

như là các
c phép to oán cơ bản mà khôngg cần phải địnhđ nghĩaa lại hay giảải thích thêêm.
Tuy nhiiên để giải thuật đó thhành chươnng trình chhạy được thhì ta phải chọn
c một cấu
c
trúc dữ liệu hợp líí để cài đặtt các phép toán này. Phần
P tiếp theo
t nói vềề các đối tưượng
cất giữ trong
t stack
k.

1.3Đối
Đ tượng cất giữ

1.3.1 Stack dùùng mảngg

Lưu trữữ stack bằng g một véc tơ lưu trữ gồm n phầần tử kế tiếếp, T là địaa chỉ ở đỉnhh
stack (làà địa chỉ tư
ương đối trong
t mảngg). Khi đó stack rỗngg khi T=-1, khi thêm môt m
phần tử vào stack thì T tăng lên 1. Ngư ược lại, khi loại một phần
p tử khhỏi stack thhì T
giảm đi 1. Cấu trú úc được môô phỏng trêên hình 2: 

Ta khai báo cấu trúc stackk:


#defin ne Max … // độ lớn
l
stack
Typededef … El lementTy ype // ki
iểu dữ
liệu
Typededef stru uct {
// mản ng lưu nội dun ng stackk
E
ElementT Type Ele ements[M
Max];
// vị trí đỉ ỉnh ngăn n xếp
i
int Top;
;
} Stack; ; Hình 3: stack
s dùng mả
ảng

Sau đâyy là một số


ố phép toáán
Tạo stacck rỗng

Ngăn xếếp rỗng là ngăn xếp không


k chứ
ứa bất kỳ một
m phần tửử nào, do đóó đỉnh củaa
ngăn xếếp không được
đ phép chỉ
c đến bấtt kỳ vị trí nào
n trong mảng
m Ækhhi khởi tạo
stack ta để Top=-1
1;
Void MakeNul
M ll(Stack k S)
{
S ÆTop= =-1;
}

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
 
DTT 
SSTTAACCKK AAD Trang 8   

Kiểm tra stack rỗng


Stack rỗng khi Top=-1
int IsEmpty(Stack S)
{
Return (S ÆTop==-1);
}
Kiểm tra stack đầy
Stack đầy khi Top=Max-1
Int IsFull(Stack S)
{
Return (S ÆTop==Max-1);
}
Lấy nội dung phần tử tại đỉnh stack :

Hàm trả về nội dung phần tử tại đỉnh của ngăn xếp khi ngăn xếp không rỗng. Nếu
ngăn xếp rỗng thì hàm hiển thị câu thông báo lỗi.
ElementType Top(Stack S)
{
if (!IsEmpty(S))
return S.Elements[S.Top];
else printf("Loi! Ngan xep rong");
}
Thêm một phần tử vào stack :

Khi thêm phần tử có nội dung x (kiểu ElementType) vào ngăn xếp S (kiểu Stack), trước
tiên ta phải kiểm tra xem ngăn xếp có còn chỗ trống để lưu trữ phần tử mới không. Nếu
không còn chỗ trống (ngăn xếp đầy) thì báo lỗi; Ngược lại, dịch chuyển Top lên trên 1 vị
trí và đặt x vào tại vị trí đỉnh mới.
void Push(Stack S,ElementType X)
{
if (IsFull (S))
printf("Loi! Ngan xep day!");
else
{
S->Top=S->Top +1;

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
 
DTT 
SSTTAACCKK AAD Trang 9  

S->E
Elements
s[S->To
op]=X;
}
}
Đẩy mộột phần tử ra
r khỏi stacck

Phần tử được xóa rar khỏi ngăăn xếp là tạại đỉnh của ngăn xếp. Do đó, khii xóa ta chỉỉ cần
dịch chuuyển đỉnh củ
ủa ngăn xếpp xuống 1 vị
v trí.
void P
Pop(Sta
ack S)
{
i (!IsE
if Empty(S)
))
S->T
Top=S->T
Top-1;
e
else
prin
ntf("Loi
i! Ngann xep ro
ong!");
}

1.3.2 Mở
M rộng sta
ack dùng mảng.
m

Nhiều khi
k ta cần thao tác cùnng một lúcc
với nhiềều stack, điều này có thể dẫn đếến
tình trạnng một stacck đầy tronng khi stacck
khác thìì trống nhiều Æ đây là hiện
Hình 4: hai stack lưu
u trữ trên cùng
g một mảng
tượng trràn cục bộ. Để xử lý trường hợpp
trên ta lưu
l nhiều stack
s vào một
m mảng
kích thưước cố định h nhưng độộ lớn mỗi stack
s thì khhông xác định.
đ Sau đây
đ là một cấu
trúc lưuu hai stack trong 1 mảảng.  
Ta thay hai đầu củ ủa stack phhát triển vềề hai phía nên
n hiện tư ượng tràn stack chỉ xẩẩy ra
khi toànn bộ không g gian nhớ dã dùng hếết. Các phéép toán trêên cách lư trữ này khhông
khác nhhiều so với trước, chỉ chú ý:
• Stack
S 1 đặt thuận chiềều Æ thao tác giống trước,
t stack 2 ngược chiều Æ
o Khởii tạo stack bằng
b cách gán Top2= =Max
o Đẩy mộtm phần tử t vào stacck thì Top22 giảm đi 1
o Lấy mộtm phần tử t khỏi stacck thì Top22 tăng lên 1
• Hai
H stack bịị tràn khi Top1>=Top
T p2

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
 
DTT 
SSTTAACCKK AAD Trang 10  

Ta cũngg có thể có nhiều hơnn hai stack


trong một
m mảng, khởi k tạo bằằng cách
chia đềuu ô nhớ cho chúng. Nếu
N một
stack phhát triển nh
hanh bị trànn mà các
stack khhác vẫn cònn chỗ trốngg thì ta
dồn chúúng: có thể đẩy stack sau nó
sang phhải hoặc lùii chính nó sang trái. 
  Hình 5: nhiều stack trê
ên cùng một mảng
m

2.2.1 Stack dùng


d DSLK
K
 
Nếu như ư ở phần trrước khi ngghiên cứu về stack dùùng mảng ta thấy rõ một nhượcc
điểm là độ lớn củaa stack đượ ợc khởi tạoo từ đầu vàà luôn cố định, điều đó đ dễ dẫn tới
stack củủa ta bị dùnng thừa thããi (chỉ dùng một phầnn nhỏ của mảng),m hoặặc có thể bị
b
tràn stacck nếu mản ng không đủ đ lớn! Phầần này xinn được giớii thiệu về một m phươngg
pháp lưuu trữ stackk mới mà có thể giải quyết
q đượcc bất cập trrên đó là dùng
d DSLK K.
Ở đây môi
m phần tử ử của stackk được lưu vào một phần p ớ gọi là núút. Các nút này
tử nhớ
ngoài chhứ thông tiin của chínnh
nó còn chứa
c hỉ của nút tiếp
địa ch
theo troong stack, nút
n cuối cùùng
trỏ về NULL.
N Về mặt trực quan
q
stack ở đây khá giiống với
Hình 6: stack
k dùng DSLK
DSLK đơn,đ chỉ khhác là ta cóó quy
định mộột phía là đỉnh
đ stack(pphía còn lạại là đáy) Æ Các thaoo tác của stack đươc
thực hiệện ở đầu củ ủa DSLK. Để tạo nênn các nút taa cần khai báo một cấấu trúc như ư
sau:

t Stack
struct k {
Elem
mentType
e Info; // thô
ông
tin
struc
ct nganx
xep *Nex
xt; // con
n
rỏ đến nút tiế
trỏ tr ếp theo
};
def stru
typede uct Stac
ck NX; / ngăn xếp
//
NX *To
Top

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
 
DTT 
SSTTAACCKK AAD Trang 11  

// con trỏ
ỏ trỏ vào
v đỉnh
h
ngăn xếp
x
Một số phép toán
n

Tạo stacck rỗng


Khởi tạo bằng cácch gán Topp bằng NUL
LL
Void MakeNul
M ll(NX *T Top)
{
*
*Top=NUL LL;
}

Kiểm tra
t sta
ack rỗng
g
Stack rỗng khi
k Top trỏ vào
o NULL
int Is
sEmpty(
(NX Top)
{
r
return (Top==NU
( ULL);
}

Lấy nộii dung phần


n tử tại đỉnnh stack :
Top trỏ đến phần tử đỉnh staack nên thôông tin ở đỉỉnh stack lấy qua Topp
Elemen ntType Top(NX Top)
{
i (!IsE
if Empty(To op))
retuurn Top p->Info o;
e
else pri
intf("Lo oi! Ngan n xep rong");
r
}

Thêm một
m phần tử ử vào stackk :
m nút có thông tin X vào stacck bằng cáách tạo ra một nút P kiểu cấu trúc,
Thêm một
nếu cấpp phát bộ nhớ
n thành công
c ữ liệu của P; sau đó thực
thì gáán thông tin X cho dữ
hện cácc thao tác con
c trỏ như ư hình vẽ 6.
6
Ngược lại nếu cấp phát không k thànnh
công thìì báo lỗi.

Hình 7: thê
êm một phần tử
t vào stack

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
 
DTT 
SSTTAACCKK AAD Trang 12  

void P
Push(NXX **Top,
,ElementtType X))
{
N *p;
NX
p
p=(NX *)
)malloc((sizeof((NX));
i
if(p!=NUULL)
{
p->IInfo=X;
p->nnext=*toop;*top
p=p;
}
e
else
prinntf(“\nLLoi cap
p phat bo
b nho!”
”);
}

Đẩy mộột phần tử rar khỏi stacck 


Nếu ngăăn xếp rỗn ng thì báo lỗi, ngược lại
l việc xóa phần tử đầu đ của staack có thể thực
hiện đơnn giản bằnng cách lưuu con trỏ Toop vào biếến trỏ P, sauu đó cho con trỏ Topp trỏ
đến phầần tử tiếp th
heo và cuốối cùng là xóa
x P.

void *
*POP (N
NX **Top
p)
{
if((*To
op)==NUL
LL
)

printf((“\nNgan
n Hình 8: xóa một phần tử
t khỏi stack
ong!”);
xep ro
else
{
NX *p=*Top;
* ;
*Top
p=(*Top)
)->next
t;
free
e(p);
}
}

Nhận xét
x

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
 
DTT 
SSTTAACCKK AAD Trang 13   

• Trong quá trình cài đặt tùy vào nhu cầu mà ta có thể dùng những thao tác nào
của stack. Trong nhiều trường hợp ta có thể gộp hai thao tác lấy nội dung phần
tử tại đỉnh stack và đẩy một phần tử ra khỏi stack thành một hàm duy nhất (sẽ
nói đến trong phần cài đặt).
• Các phép toán trên chỉ là các phép toán cơ bản nhất. Ta có thể thiết kế ra nhiều
phép toán khác tổng hợp từ các phép toán cơ bản này. Ví dụ khởi tạo stack từ
một tập phần tử cho trước hay xóa toàn bộ một stack, hoặc có thể sao chép
stack…

2.3 Các ứng dụng của Stack 
 
Mặc dù cấu trúc stack rất đơn giản nhưng ứng dụng của stack là rất rộng: từ áp
dụng để giải quyết các bài toán đơn giản như chuyển đổi cơ số đến các bài toán
phức tạp hơn như tính toán một biểu thức toán học bất kì hay như một hệ thống các
bài toán dùng stack khử các bài toán đệ quy để làm tối ưu trương trình. Stack có
ứng dụng đặc biệt để tạo cơ chế hoạt động cho các trương trình dịch. Stack ứng
dụng để nhúng một phần vào các trương trình lớn như hệ điều hành, trương trình
ứng dụng …

2 Cài đặt (trên C)

2.1 Mô phỏng hoạt động của stack 

Đây là một trương trình đơn giản mô tả cấu trúc vào/ra của stack; chủ yếu để thấy
rằng cấu trúc stack thì hoàn toàn đơn giản. Trưong trình gồm 4 thao tác:
1.push 2.pop 3.duyet 4.thoat
Dùng DSLK để mô tả stack
struct phantu {
char hoten[25];
struct phantu *next;
};

Trích dẫn cài đặt; file chạy trong thư mục Basic
#include<stdio.h>

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
 
DTT 
SSTTAACCKK AAD Trang 14   

#include<conio.h>
#include<string.h>
#include<alloc.h>
struct phantu {
char hoten[25];
struct phantu *next;
};
struct phantu *top;
void push(char *);
char *pop();
void duyet();
void main()
{
int c;char s[25];
clrscr();
top=NULL;
do {
printf("\n1.push 2.pop 3.duyet 4.thoat ");
scanf("%d%*c",&c);

if(c==1)
{
printf("\nHo ten ");gets(s);push(s);
}
if(c==2)
{

strcpy(s,pop());

if(strcmp(s,"")!=0)

printf("\nPT lay ra: %s",s);


else

printf("\nDS rong");
}
if(c==3) duyet();
} while(c!=4);
}// End of Main
//-----------------------
void push(char *s)

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
 
DTT 
SSTTAACCKK AAD Trang 15   

{
struct phantu *p;
p=(struct phantu
*)malloc(sizeof(struct phantu));
strcpy(p->hoten,s);
p->next=top;
top=p;
}
//-------------------------------
char *pop()
{
char s[25]="";
char *p;
if(top==NULL) return "";
strcpy(s,top->hoten);
top=top->next;
p=(char *)s;
return p;
}
//0-------------------
void duyet()
{
struct phantu *p;
if(top==NULL) printf("\nDS rong");
for (p=top;p!=NULL;p=p->next)
printf("\n%s",p->hoten);
}

2.2 Bài toán chuyển đổi giữa các cơ số
 
program BASE_N
Source sode file: BASE_N.CPP
Executed file: BASE_N.exe

Chuyển đổi cơ số từ hệ thập phân sang hệ nhị phân


(sử dụng stack lưu trữ dưới dạng mảng)

™ Chức năng của chương trình.


• Chuyển đổi số thập phân sang số nhị phân 32 bit.

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
 
SSTTAACCKK AAD
DTT Trang 16

• Input: số thực bất kỳ có giá trị trong đoạn [2147483648.0 ;


2147483647.0],số nguyên đầu vào sẽ là cận dưới của số thực nhập vào.
• Output: một số nhị phân 32 bit
™ Lưu đồ thuật giải.
™ Nhập số thập phân d. Bước này
xác định đầu vào, đầu vào có thể
là một số thực bất kỳ -
2^16<=x<=2^16-1. Khi đó d=int
(x) tức là lấy phần nguyên của x.
™ Khi d<0 thì biến cờ sign=1 để
đánh dấu đầu vào là 1 số âm va
gán d=-d.
™ Chuyển đổi thập phân sang nhị
phân được thực hiện nhờ hàm int
trans(long int, int *) (sẽ được nói
kỹ trong phần sau)
™ Tính mã bù 2; được thực hiện bởi
2 việc: đảo bit và cộng thêm bit 1.
™ Có muốn làm lại : cho phép
người dùng tiếp tục sử dụng
chương trình mà khoongphiar
khởi đọng lại nó.
™ Stack ADT sử dụng trong chương
trình.
™ Stack trong chương trình được
lưu trữ dưới dạng mảng.
™ Khai báo:const int
bit_rate=32;

int stack[bit_rate];
int T=0;
™ Các thao tác cơ bản trên stack:
- Push: đẩy một phần tử vào stack:

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 17

int push(int *stack,int *T,int x)


{
if(*T>bit_rate) {_error=2;return 0;}
(*T)++;
stack[*T]=x;
return 0;
}

- Pop: lấy 1 phần tử ra khỏi stack.


int pop(int *stack,int *T)
{
if(*T<0) {_error=2;return 0;}
(*T)--;
return(stack[*T+1]);
}

Phân tích các hàm trong chương trình


Hàm khởi tạo:
- Khai báo: long int initial(int *bin)
- Chức năng: nhập trả lại số thập phân cần chuyển đổi sang nhị phân.
- Source code:
long int initial(int *bin)
{
double x=0.0;
for(int i=0;i<bit_rate;i++) bin[i]=0;
do{
if(x) {printf("\nDomain error!");getch();}
intro();
printf("\nEnter 1 decimal number:");
scanf("%lf",&x);
}
while(!((x>=-2147483648.0)&&(x<=2147483647.0)));
return((long int)x);
}

- Phân tích: đầu vào là một số thực bất kỳ. sau khi kiểm tra điều kiện
(((x>=-2147483648.0)&&(x<=2147483647.0))) thì hàm sẽ trả về
phần nguyên của x là (long int) x. Nếu vi phạm điều kiện thì hàm
sẽ đưa ra thông báo lỗi và yêu cầu nhập lại.
Hàm chuyển mã thập phân dương sang nhị phân.
- Khai báo: int trans(long int x, int *bin)
- Input: số thập phân.
- Output: số nhị phân 32 bit.

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 18

- Source code:
int trans(long int x, int *bin)
{
int stack[bit_rate];
int i=0,T=0;
do{
push(stack,&T,x%2);i++;
x=x/2;
}while(x);
i=0;
while(T){
bin[bit_rate-T-1]=pop(stack,&T);
}
return 0;
}
- Phân tích: vòng lặp do{…}while. Là phần chính của hàm này. Nó
thực hiện đưa(push) phần dư của phép chia x%2 vào stack. Vòng lặp
thứ 2 sẽ lấy các phần tử trong stack và đưa vào mảng bin[] chính là
mảng kết quả.
Hàm mã bù hai.
- Khai báo: int two_complement(int *bin)
- Input: số nhị phân.
- Output: mã bù 2 của số nhị phân đầu vào.
- Source code:
int two_complement(int *bin)
{
int i,j,r=0;
for(i=0;i<bit_rate;i++)
bin[i]=~bin[i];
do{
if(bin[i]) {bin[i]=0;r=1;}
else {bin[i]=1; r=0;}
} while(r!=0);
return 0;
}

- Hàm bao gồm 2 hàm con:


Hàm đảo bit.
Khai báo: int NOT(int *bin)
Input: số nhị phân.
Output: mã bù 1 của số nhị phân.
Source code:

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 19

int NOT(int *bin)


{
for(int i=0;i<bit_rate;i++)
if(bin[i]) bin[i]=0; else bin[i]=1;
return 0;
}

Hàm cộng thêm bit 1 vào 1 số nhị phân.


Khai báo: int add_a_bit(int *bin)
Input: số nhị phân.
Output: số nhị phân đã cộng thêm 1.
Source code:
int add_a_bit(int *bin)
{
int r=1,i=0;
while(r){
if(bin[bit_rate-i-1]==0){
bin[bit_rate-i-1]=1;
r=0;
}
i++;
} return 0;
}
Phân tích: biến int r; là biến lưu giá trị nhớ, vòng lặp
while kết thúc khi r=0. Nghĩa là số nhị phân đã được
cộng thêm 1.
Phân tích đánh giá độ phức tập tính toán
Ta có thể tính được độ phức tạp tính toán của các hàm (functions)
- Các hàm initial, pop, push, intro tốn thời gian là hằng số
- Hàm trans trong tình huống tồi nhất là thược hiện bit_rate lần lệnh
push(stack,&T,x%2) +bit_rate lần gọi lệnh pop.
- Hàm NOT thục hiện đúng bit_rate lần câu lệnh so sánh bin[i]=0.
- Hàm add_a_bit. Trong tình huống tồi nhất là thực hiện bit_rate lần
câu lệnh so sánh r==0.
Như vậy nếu bit_rate là hằng số thì thời gian tính của các hàm là
hằng số.
Các ví dụ
VD1: input: 1213
Output: Binary
number:0000.0000.0000.0000.0000.0100.1011.1101
VD2: input:1.023

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 20

Output: Bin
nary
number:00 000.0000.000
00.0000.000
00.0000.0000.0001
VD3: inputt: -1213
output: Binary
number:1111.1111.111 11.1011.0100.0011
11.1111.111

2.3 Polish Pro


P oblem :( bài
b toán Balan)
B chuuyển biểu thức dạng trung tốố
sang dạngg hậu tố và
à tính biểu
u thức hậu
u tố

2.3.1 Cơ
C sở lý th
huyết

Xét mộtt biểu thứcc toán học gồm


g các tooán hạng: A,
A B, 1, 2… …và các tooán tử: +, -, *,
/… giả sử chỉ xét các toán tửử mà thực hiện
h phép toán với hai toán hạnng thì toán tử
bao giờ cũng đặt giữa
g các tooán hạng (kkí pháp trunng tố(Infixx Notation))). trong nhhiều
trường hợp
h ta phảải đặt thêm các cặp dấấu ngoặc để đ phân biệệt thứ tự tínnh toán củaa
các phépp toán. Ví dụ hai biểuu thức

1+2*3 // =7
(1+2)*3 là hoàn
h toàn khác
k nhau. // =9

Trong tooán học ph hép nhân vàv phép chiia có mức ưuư tiên caoo hơn phépp cộng và phép
p
trừ nên ở biểu thứức một 2*3 sẽ được tíính trước, sau
s đó mớii cộng thêm m 1. Cặp dấu
d
ngoặc cóc mức ưu tiên cao nhhất trong các phép tooán nên ta phải
p tính biểu thức (11+2)
trước saau đó mới nhân
n với 3.
3 Trong trư c phép tooán có cùnng mức ưu tiên
ường hợp các
thì tính lần lượt từ
ừ trái qua phải.
p Ví dụụ biểu thứcc :

• 1-2+3-4+5 tính lần lư ượt từ trái qua


q
p
phải. (hình 9)).
Ví dụ một
m biểu thứ ức chứa cáác toán tử có
c
mức ưuu tiên khác nhau.
• 5+4*3-2/1^^0 (dạạng trung tố)
t
Thứ tự tính
t toán sẽ là :
• 1^0=1 (5+4*33-2/1)

• 4*3=12 (5+12--2/1) Hình 9: tính biểu thức

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
SSTTAACCKK AAD
DTT Trang 21

• 2/1=2 (5+12-2)
• 5+12=17 (17-2)
• 17-2=15 15

Tuy nhiên trong một biểu thức thường không thể thiếu những dấu ngoặc với mục
đích thu gọn biểu thức. Chẳng hạn ta có thể viết A*(B+C+D) hoặc
A*B+A*C+A*D ; thì kết quả đều như nhau. Nhưng cách viết thứ nhất ngắn hơn và
sẽ tính nhanh hơn ! Tuy nhiên một nhà toán học Balan J.Lukasiewicz đã phát hiện
rằng dấu ngoặc cũng không cần thiết khi ta biểu diễn biểu thức số học theo kí pháp
hậu tố (Postfix Notation) hoặc tiền tố (Prefix Notation). Chúng được gọi chung là
kí pháp Balan (Polish Notation).

2.3.2 Biểu thức hậu tố và tiền tố

Với kí pháp hậu tố, toán tử đặt sau các toán hạng.
Ví dụ:
Toán tử hai toán hạng
• A-B (trung tố) A B - (hậu tố) // phép trừ hai ngôi
• A/B AB/
• A^B AB^
• A*B+C AB*C+
• (B+C)*A BC+A*
• A/B^(C+D) ABCD+^/
Toán tử một toán hạng
• A! A!
• ~A A~ // quy ước ~ là phép trừ môt ngôi
Tổng hợp
• (A!+B!)/C^D A!B!+CD^/
Với kí pháp tiền tố, toán tử đặt trước các toán hạng
• A-B -AB
• A*(B+C) *A+BC
• A! ! A …v…v
Kí pháp hậu tố và tiền tố chỉ khác nhau về cách đặt các toán tử nên việc tính toán
trên hai hang này tương tự nhau. Ta sẽ chỉ nghiên cứ về biểu thức hậu tố.

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 22

2.3.3 Tính
T giá trrị biểu thứ
ức hậu tố

Xét mộtt biểu thứcc hậu tố ở trên:


t ABC+A* // (
(B+C)*A
Ta nhậnn thấy khi duyệt
d biêu thức từ tráái qua phảii hễ gặp một toán tử (+) thì hai
toán hạnng trước đó ó(B, C) sẽ được tác động
đ bởi tooán
tử này để
đ tạo thàn nh một toánn hạng mớii (B+C) chho
các toánn tử tiếp th
heo (hình 9).
• Nếu
N ký tự được đ đọc làà toán hạngg(B, C) thìì ta
lưưu giá trị của
c nó.
• Nếu
N ký tự đó đ là toán tử(+)
t thì lôôi hai toán hạng
h
b đã lưu trước
bảo t đó đểể tác động vào chúngg
(BB+C).
• Tính
T toán kết
k thúc khii duyệt hếtt. Giá trị cuuối Hình
h 10: tính biểu
u thức hậu tố
cùùng được bảob lưu chhính là kết quả.q
Nhận xéét:
• Các
C toán hạạng được đọc đ sau lại kết hợp vớ ới toán tử đọc
đ trước (các ( toán hạng
h
b lưu sau
bảo u được lôi ra
r trước). Do D đó ta ngghĩ tới mộtt CTDL kiểểu stack đểể
lưưu giữ các kết quả troong quá trìình tính toáán. Giải thuuật được mô m tả qua ví v dụ
saau.
Tính giáá trị biểu th
hức hậu tố: 2 3 4 + 5 6 - - *. Cáác thao tác được minhh họa trên
hình 10.
Ta thấy việc tính biểu
b thức hậuh tố là hooàn
toàn “m
máy móc” và v có thể càài đặt đượcc
lên các ngôn ngữ lâp trình.

2.3.4 Giải
G thuật

Tất cả các
c thành viên
v trong nhómn đều
muốn tự ự cài đặt bàài toán một mình, nênn
n bản. Chúnng em xin giới thiệu hai trươngg trình tiêu biểu:
có rất nhhiều phiên
1. Một
M cài đặtt bằng CTD DL kiểu Hình 11: tính biểu thức hậu tố dùng
d stack
m
mảng.Trươn ng trình tênn là Balan1.c
trrong thư mục
m Balan1

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
SSTTAACCKK AAD
DTT Trang 23

2. M
Một cài đặtt bằng CTD DL kiểu daanh sách liêên kết (Ballan2).
C hai CT
Cả TDL này đề ều được đềđ cập ở phầnp 1, phhần cài đặặt cụ thể và
g thích chi
giải c tiết đưược nêu ở File word d cùng thư ư mục. mỗ ỗi thư mụcc
g
gồm:
o File nguồn
n + file
f chạy
o File word giải thích trươ ơng trình vàv hướng g dẫn sử dụng.
d
Không phụp thộc vàov cách càài đặt như thế
t nào; tấtt cả các cách cài đặt đều phải tuuân
theo giảải thuật sau
u:
Procedure Ca alculate ePostfix xExpress sion(P,V Value)
// thủ ủ tục này n tínhh giá tr rị biểu thức hậ ậu tố P,P kết quả q
gán cho Valu ue
// sử ử dụng một m stacck S với i T trỏ tới đỉn nh; khở ởi tạo
stack k rỗng
1. Thêm
T dấuu “)” và ào cuối biêu thức t P để
đ làm dấu d kết
t
thúc
2. Repeat
R
a. Đọc ký tự X trong g P khi duyệt từ t trái qua phả ải
b. Nếu X là to oán hạn ng thì
i. call PUSH(S,T
P T,X);
c. Else e // nếuu X là toánt tử thì và tác động X và ào.
i. Call POP(S,T,
P ,Y); // lấ ấy hai toánt hạnng
trong stack ra r
ii. Call POP(S,T,
P ,Z); // và à chứa vào v Y và à Z
iii. W = Z (X) Y; // tác độn ng X và ào Y và Z
W
iv. Call PUSH(S,T
P T,W); // đẩy giá trị tính t đượợc
vào sttack
3. Until
U ặp dấu kết
gặ k thúc c “)”;
4. Call
C POPP(S,T,Va alue);
5. Return
R

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
SSTTAACCKK AAD
DTT Trang 24

Để có biểu
b thức hậu tố ta cầnn thao tác
chuyển từ biểu thứ ức trung tốố( dạng tự
nhiên) sang
s hậu tố
ố thao tác này
n được
thực hiệện cũng bằằng một giảải thuật dựaa
vào stacck.

2.3.55 Chuyểnn đổi trungg tố sang


hậu tốT
T

Trong biêu
b thức trrung tố nếuu xuất hiênn
dấu mở ngoặc “(“ thì phải xuuất hiện dấấu
đóng nggoăc “)” tưương ứng. DoD các dấuu
ngoặc lồồng nhau thì
t dấu mở ngoặc
trước lạại ứng với dấu
d đóng ngoặc
n sau.
Thêm nữa
n khi gặp p toán tử thhì phải duyyệt
đến toánn hạng thứứ hai rồi mớới đặt toánn tử đó sau toán hạng thứ hai. Do
D đó ta sẽ
dùng một
m stack đểể lưu các dấud mở ngooặc (để chờ ờ các dấu đóng
đ ngoặcc tương ứnng)
và lưu các
c toán tử ử để chờ toáán hạng thứ ứ hai tương ứng. Ta xét ví dụ
Ví dụ: chuyển
c biểểu thức trung tố: 2*(((3+4)-(5-6)6)) sang dạạng hậu tố.

Gọi Q là biểu thứcc trung tố, ta cần chuuyển Q sang biểu thứcc P dạng hậu h tố thông
qua stacck S. Thêm m dấu “)” vào
v Q để lààm dấu kết thúc và tư ương ứng làà thêm dấuu
“(“ vào S. Thao táác minh họọa trên hìnhh 11:
• Bước
B 1: choo “2” (toánn hạng) vàoo P
• Bước
B 2 4:: đẩy các dấud ngoặc và v toán tử vào
v S
• Bước
B 5: choo “3” vào P
• Bước
B 6: đẩyy “+” vào S
• Bước
B 7: choo “4” vào P
• Bước
B 8: loạại “+” ra khhỏi S và chho nó vào P,
P sau đó looai “(“ khỏỏi S
• Bước
B 9 10 0: đẩy “–“ và ( vào S
• Bước
B 11: 5 vào P Hìình 12: chuyển biểu thức trrung tố sang hậu
h tố
• Bước
B 12: đẩẩy “–“ vàoo S
• Bước
B 13: 6 vào P

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
SSTTAACCKK AAD
DTT Trang 25

• Bước 14: loại “–“ khỏi S và cho nó vào P, sau đó loại “(“ khỏi S
• Bước 15: giống bước 14
• Bước 16: loại “*” khỏi S và cho nó vào P, sau đó loại “(“ khỏi S

2.3.6 Giải thuật


Procedure Polish(Q,P)
1. Thêm “(“ vào cuối Q
2. Call PUSH(S,T,”(“);
Repeat
1. Đọc X từ Q khi duyệt từ trái qua phải
2. Case X
a. X là toán hạng: cho X vào P
b. X là dấu mở ngoặc: call PUSH(S,T,”(“);
c. X là toán tử:
i. while thứ tự ưu tiên của S[T] >= thứ tự ưu
tiên của X
1. Call POP(S,T,W);
2. Cho W vào P
ii. Call PUSH(S,T,X);
d. X là dấu đóng ngoăc:
i. Repeat
1. Call POP(S,T,W) ;
2. Cho W vào P
ii. Until gặp dấu “(“
iii. Loại “(“ khỏi S
Until stack S rỗng
Return

Hai trương trình Balan1 và Balan2 và mỗi file word của nó hướng dẫn chi tiết
cách cài đặt và các giải thuật sử lý xâu cho mỗi một trương trình.

2.3.7 Cài đặt thuật toán balan dùng DSLK ứng dụng stack

Các phần

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 26

1. Phá
át biểu
u bài toán
t
2. Sơ đồ tín
nh toán
n
3. Chu
uẩn hóa
a xâu
4. Chu
uyển xâ
âu sang ố
g dạng hậu tố
5. Tín ố
u thức hậu tố
nh biểu
6. Các
c phép xử lý lỗi
7. ức tạp của gi
Ví dụ và độ phứ iải thu
uật
Phần nàày giải thícch về cài đặặt còn giải thuật và cấu trúc dữ liệu và giảải thuật đã nói
kĩ ở trênn

1. Phátt biểu:

Đầu vàoo: bài toánn nhập vàoo một biểu thức(BT) toán
t học dư
ưới dạng xâu
x chứa cáác
phần tử
ử:
• Toán
T hạng: ( 3 lọai)
o Các hằng
h số: PII=3.14…, E=2.71…,
E , và các hắnng số thực.
o Các biến:
b X,Y,ZZ,I,J,K kiểểu thực.
Trrong biểu thhức nhập có
c thể chứaa 6 biến trêên; nếu biếến
nàào có
troong BT
nhhập vào sẽ
đưược nhập
giáá trị sau
khhi nhập
xoong cả BT.
• Toán
T tử: (14
4 loại)
o +-*/
o Phép trừ một nggôi: -
(cho phép ký hiiệu giống
phép trừ hai ngôi)
o ^ // mũ
o ! // giai
thừa

H
Hình 13: sơ đồ
ồ tính toán biê
êut thức balan

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
SSTTAACCKK AAD
DTT Trang 27

o Sin, cos, tg, ln, sqr(căn bậc hai), abs (trị tuyệt đối), flo(lấy phần
nguyên), rnd (hàm random)

Đầu ra: kết quả là một số thực tính toán được.


2. Sau đây là sơ đồ tính toán:

Nhập một sâu S độ dài tối đa 80 ký tự nếu sâu khác rống thì ta chuẩn hóa xâu,
ngược lại thì nhập lại sâu.
3. Chuẩn hóa xâu gồm:
• Chuyển tất cả thành chữ hoa
• Loại bỏ các dấu cách
• Su ly toan tu '-' một ngôi,VD:(-1-2)->(0-1-2) (chèn số ‘0’ vào trước toán tử
một ngôi.
• Sử lý thêm đóng ngoặc: người dùng không cần phải gõ các dấu đóng ngoắc
còn lại của biểu thức; trương trình sẽ đếm số mở ngoặc và tự điền số đóng
ngoặc.
Hàm chuẩn hóa chỉ chuẩn hóa sơ qua, các phép sử lý lỗi được rải rác
trong các hàm : chuyển hậu tố và tính biểu thức hậu tố.

Khai báo một cấu trúc:

struct nganxep {
char xau[20]; // chứa một phần tử của biểu thức
struct nganxep *next;// trỏ đến phần tử tiếp theo trong stack
};
typedef struct nganxep NX;
khai báo hai biến trỏ toàn cục kiểu NX
NX *S=NULL,*P=NULL; // P được dùng để chứ biểu thức hậu tố dạng DSLK stack
// S là stack khác làm thành phần chung chuyển giúp
chuyển biểu thức dạng xâu P; và tính BT hậu tố P (S chứa giá trị cuối cùng)
double X,Y,Z,I,J,K,giatri; // 6 biến & đáp số
int isX=0,isY=0,isZ=0,isI=0,isJ=0,isK=0;
6 biến này xét xem các biến X,Y.. có mắt trong biểu thức nhập vào không ?
Giả sử X có mặt thì isX=0 và ngược lại.

4. Chuyển biểu thức sang dạng hậu tố nhờ hàm : void hauto(char *bieuthuc) ;

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 28

Hàm nàày sử dụng một số hààm nhỏ kháác được liệt kê trong phần Phototype ở coode.

4: chuyển xââu sang cấu


Hình 14 u trúc stack kiểu DSLK

void PU USH(NX **S,char *sstr); //đẩy một


m nút có giág trị str vào
v stack S
char *POP(NX ** *,char *); //l
/loại 1 phầnn tử ở đỉnhh stack, đồnng thời trảả lại
kết quả là xâu của a đỉnh
int uutieen(char *);; //ttrả về số ưuu tiên của một toán tử
t
int istoaantu(char); //kký tự có phải là toán tử không
int lentooantu(char)); ///trả về độ dài
d toán tử ử VD: sin laa 3
int isnum m(char *); //k
/kiểm tra một
m xâu có là số khôngg? (doublee)
int istoaanhang(chaar *); //kiểm m tra có là toán hạngg không

Trích dẫẫn hai hàm


m quan trọnng

void PUSH(NX
P **top,cha
* ar *str)
{
NX *p;
p=(NX *)mallocc(sizeof(
(NX)); //
/ cấp phát độnng
vùng nhớ
n cho phần
p tử p thêm vàào
y(p->xau,str);
strcpy /
// gán giá trị
ới này
hần tử mớ
cho ph
p->nex
xt=*top;**top=p; /
// hai thao tá ác
đẩy và
ào stack
}
//------------
--------- ------------------
---------
---// cơ chế ế

Bài tập lớ
ớn môn cấu trúc dữ liệu và giải thuậ
ật Giáo viên hướ
ớng dẫn : Ng
guyễn Đức Nghĩa
N
SSTTAACCKK AAD
DTT Trang 29

hoạt động đã được nêu rõ trong file word chính


char *POP(NX **top,char *str)
{NX *p;
if((*top)==NULL) return ""; // nếu stack chua
có gì thì trả về sâu rỗng
strcpy(str,(*top)->xau); // copy giá trị ở
đỉnh vào con trỏ *str
p=*top;*top=(*top)->next; // thực hiện thao
tác loại phần tử đỉnh
free(p); // giải phóng vùng nhớ
return str; // trả lại giá trị của
đỉnh
}
Thao tác POP cho phép có hai cách để lấy giá trị ở đỉnh.

• Chú ý để phép toán thực hiện đúng đắn biến top đầu vào phải khai báo con trỏ
của con trỏ

Trong hàm hauto ta mã hóa các toán tử và toán hạng như sau :
• Sin S
• Cos C
• Tg T
• Ln L
• Abs A
• Rnd R
• Flo F
• Sqr Q
• Pi P
Hàm tính độ dài toán tử sử dụng khi duyệt biểu thức nhập vào. Ví dụ khi ta nhập
biểu thức :
Sin ( cos ( tan( pi / 4
Sau khi chuẩn hóa thành :
1. SIN(COS(TG(PI /4)))
Duyệt từ trái qua phải và mã hóa:
2. Vị trí 1gặp ‘S’ đoán là “SIN” tính độ dài toán tử này =3 lưu ‘S’
duyệt tiếp vị trí thứ 1+3=4; là ‘(‘

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 30

Chú ý ta có quan tâm đến nhập có đúng SIN hay không nên cần quan
tâm đến ‘I’ và ‘N’. Chẳng hạn SIM báo lỗi
Sau khi chuyển hậu tố biểu thức trên thành dạng stack P như sau:
NULLP4/TCS (dạng hậu tố) (***)
Chú ý:
Quy định thứ tự ưu tiên của các phép toán(càng nhỏ càng có mức ưu tiên cao)
• 0:(
• 1:+-
• 2:*/
• 3:SCTQLR
• 4:^
• 5:!
• 6:AF
Hàm kiểm tra là toán tử ? khi ký tự đó là một trong các giá trị :
+ - * / ^ ! S C T Q A L R F thì trả về 1 ; ngược lại trả về 0

Kiểm tra một sâu là số khi nó chỉ chứa các chữ số và có thể duy nhất một dấu ‘.’
Nhìn vào dạng hậu tố (***) ở trên mặc dù có dạng hậu tố nhưng bị ngược và ta
không thể tính BT này bằng cách duyệt qua danh sách. Ta muốn duyệt từ P trong
khi cấu trúc trên chỉ cho duyệt từ S !!!
Cần một hàm đảo stack P ở trên thành : P 4 / T C S NULL
Trích dẫn :

void DAO(NX **top)


{
NX *p,*q=NULL,*s;
p=(*top)->next;
(*top)->next=NULL;
if(p!=NULL){ q=p->next;p->next=*top;}
while(q!=NULL)
{
s=q;q=q->next;
s->next=p;p=s;
}
if(p!=NULL)*top=p;
}

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 31

Sau khi đã được một biểu thức hâu tố hoan chỉnh kiểu stack dùng DSLK ; trương
trình sẽ kiểm tra có biến nào được nhập không. Nếu có thì đề nghị người dùng
nhập các giá trị cho nó.

5. Viêc còn lại là tính biểu thức hậu tố và đưa kết quả ra màng hình :

Thuật toán để tính đã được đề cập chi tiết trong file word chính ; ở đây ta chỉ giải
thích một số điển lưu ý :
• Mỗi phần tử của stack là một cấu trúc có hai thành phần : « giá trị » là
một xâu độ dài cố định 20 byte, và con trỏ next (2 byte) trỏ tới phần tử
tiếp theo. Khi ta duyệt qua xâu biểu thức cần tính, với mỗi một phần tử
nhận biết được chẳng hạn SIN thì ta lưu ‘S’ dưới dạng một xâu độ dài 20
cần một hàm nhỏ để chuyển đổi 1 ký tự char một xâu ! Đối với các
số nhập vào chỉ cho phép số có đọ dài không quá 20. Các hằng số như PI
và E thì được Turbo C++ 3.0 hỗ trợ.
• Vì biểu thức hậu tố (dạng DSLK stack) có chứa các biến
X,Y,Z,I,J,K( các biến ở dạng xâu) nên ta cần một hàm chuyển để tính

char *chuyen(char *s)


{
if(strcmp(s,"X")==0) return gcvt(X,20,s);
else if(strcmp(s,"Y")==0) return gcvt(Y,20,s);
else if(strcmp(s,"Z")==0) return gcvt(Z,20,s);
else if(strcmp(s,"I")==0) return gcvt(I,20,s);
else if(strcmp(s,"J")==0) return gcvt(J,20,s);
else if(strcmp(s,"K")==0) return gcvt(K,20,s);
else return s; // là các số
}

6. Một số thao tác sử lý lỗi được chèn vào trương trình :


Trong hàm chuyển hâu tố như :
• Kiểm tra nhập có đúng không ? nếu không báo lỗi.
o Nếu số nhập vào dài quá 20 Syntax error: Number is too long!
o Nếu nhập sai SIM Syntax error: “SIM” It must be \"SIN\" or
\"SQR\"." …vv..

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 32

Trong hàm tính BT hậu tố


• Nếu chia cho 0 Errror: divide by zero!
• Căn số âm Errror: Sqr(a negative number)!
• Tính (-3)! Errror: Factorial(a negative number)!
7. Các ví dụ và độ phức tạp của giải thuật
Cách nhập số liệu chỉ là một xâu biểu thức với các thành phần cho phép. Phần giao
diện Dos nêu rõ cách nhập; nếu nhập sai báo lỗi.
Độ phức tạp của thuật toán chỉ là O(n)

Phần cài đặt bằng mảng không đưa ra ở đây, code và hướng dẫn được nêu rõ trong
thư mục balan1.

2.4 Một số bài toán khử đệ quy (Derecursion )

Trước hết, ta nhắc lại khái niệm đệ qui. Ta nói một đối tượng là đệ qui nếu nó bao
gồm chính nó như là một bộ phận hoặc nó được định nghĩa dưới dạng của chính nó.
Khử đệ qui ở đây là biến một thủ tục đệ qui thành thủ tục chỉ chứa vòng lặp mà
không làm ảnh hưởng gì đến các yếu tố khác chứ không phải là thay đổi thuật toán.
Khi một thủ tục đệ qui được gọi từ chương trình chính, ta nói: thủ tục được thực
hiện ở mức 1 (hay độ sâu 1 của tính đệ qui). Nhưng khi thực hiện ở mức 1 lại gặp
lời gọi đến chính nó, nghĩa là phải đi sâu vào mức 2 và cứ như thế cho tới một mức
k nào đấy. Rõ ràng mức k phải được hoàn thành xong thì mức (k-1) mới được thực
hiện. Lúc đó ta nói: việc thực hiện được quay về mức (k-1)

Khi từ một mức i, đi sâu vào mức (i+1) thì có thể có một số tham số, biến cục bộ
hay địa chỉ (gọi là địa chỉ quay lui) ứng với mức i cần phải được bảo lưu để khi
quay về tiếp tục sử dụng. Còn khi từ mức i quay về mức (i-1), các tham số, biến
cục bộ và địa chỉ ứng với mức (i-1) phải được khôi phục để sử dụng.

Như vậy, trong quá trình thực hiện, những tham số, biến cục bộ hay địa chỉ bảo lưu
sau lại được khôi phục trước. Tính chất “vào sau ra trước” này dẫn tới việc sử dụng
stack trong việc cài đặt các thủ tục khử đệ qui. Thực chất của việc khử đệ qui là
chúng ta phải làm công việc của một trình biên dịch. Mỗi khi có lời gọi đến chính

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 33

nó thì stack sẽ được nạp để bảo lưu các giá trị cần thiết. Còn mỗi khi thoát ra khỏi
một mức thì phần tử ở đỉnh stack sẽ được lấy ra để khôi phục lại các giá trị cần
thiết cho mức tiếp theo.

Ta có thể minh hoạ việc khử đệ qui bằng một ví dụ đơn giản sau: Bài toán duyệt
cây.
Giả sử có một cây nhị phân với các nút được định nghĩa như sau:
struct
{
int data;
node *left, *right;
} node;
Xuất phát từ nút gốc, cần duyệt qua tất cả các nút của cây theo thứ tự trước (post
order).Thủ tục đệ qui sẽ như sau:
void postOrder (node* t)
{
if (t != NULL)
{
visit(t);
postOrder(t->left);
postOrder(t->right);
}
}
Ta có thể dễ dàng khử lời gọi đệ qui thứ 2 như sau:
void postOrder (node *t)
{
LABEL_0: if(t==NULL) return;
visit(t);
postOrder(t->left);
t= t->right;
goto LABEL_0;
}

Kỹ thuật trên gọi là khử đệ qui phần cuối. Để khử lần gọi đệ qui còn lại đòi hỏi
phải tổ chức một ngăn xếp để lưu giữ các biến cục bộ, các tham số, và sử dụng các
hàm thao tác trên ngăn xếp:
push(t): đặt biến t vào đỉnh ngăn xếp
pop: lấy 1 giá trị ở đỉnh ngăn xếp

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 34

isEmpty(): báo hiệu ngăn xếp đã rỗng


Thủ tục viết lại như sau:
void postOrder(node *t)
{
label LABEL_0, LABEL_1, LABEL_2;
LABEL_0:
if(t==NULL) goto LABEL_1;
visit(t);
push(t);
t= t->left;
goto LABEL_0;
LABEL_2:
t= t->right;
goto LABEL_0;
LABEL_1:
if(isEmpty()) return;
t= pop();
goto LABEL_2;
}

Bây giờ, loại bỏ hoàn toàn các chỉ thị goto và tránh trường hợp nạp các nút rỗng
vào stack ta có thủ tục duyệt cây không đệ quy chuẩn như sau:
void postOrder (node *t)
{
push(t)
do
{
t= pop();
if (t->left != NULL) push(t->left);
if (t->right != NULL) push(t->right);
}
while(!isEmpty());
}
Sau đây là ví dụ minh hoạ cụ thể hơn cho kỹ thuật này, cài đặt sắp xếp nhanh
(QuickSort) khử đệ quy:

int stackLeft[100];
int stackRight[100];
int top= 0;

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 35

push (int left, int right)


{
top++;
stackLeft[top]= left;
stackRight[top]= right;
}
pop (int *left, int *right)
{
*left= stackLeft[top];
*right= stackRight[top];
top--;
}
int isEmpty()
{
return (top==0?1:0);
}
void quickSort (int *x, int n)
{
int left, right, i, j, temp, p;
push(1, n);
do
{
pop(&left, &right);
i= left;
j= right;
p= x[(left+right)/2];
do
{
while(x[i]<p) i++;
while(p<x[j]) j--;
if(i<=j)
{
temp= a[i];
a[i]= a[j]:
a[j]= temp;
i++;
j--;
}
while (i<=j);
if(i<right) push(i, right);
if(j>left) push(left, j);

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 36

while (isEmpty() != 0);


}

2.5 Đóng gói stack bằng lớp(Class) trong C++

Phần này nêu cách biểu diễn stack bằng lớp gồm các thuộc tính và phương thức
trên thuộc tính đó. Gồm hai ví dụ mô phỏng trong thư mục “stack in C++”. Một ví
dụ dùng mảng (tên là Stack_Arr) và một ví dụ dung DSLK (tên là Stack_Lis).
StackArr

Trương trình gồm hai file: stackarr.h (header) và stackarr.cpp (application). File
header khai báo cấu trúc lớp (để không “cồng kềnh”; trong file này viết luôn phần
thực hiện (implementation).
Ta khai báo một template:

template <class stack_type, int max_size=10>


class stack
{
public: // các phương thức
stack(); // constructor
bool push (const stack_type&); // đẩy một phần tử
vào stack
bool pop (stack_type&); // đẩy phần tử ở
đỉnh ra khỏi stack
bool get_top(stack_type&) const;// lấy phần tử ở đỉnh
stack
bool is_empty() const; //stack có rỗng không?
bool is_full() const; //stack có đầy không?
private://các thuộc tính
int top; // chỉ số ở đỉnh stack
stack_type items[max_size]; // mảng chứa các thành
phần stack
};

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 37

Stack_type là kiểu dữ liệu phần tử của stack , có thể là các kiểu dữ liệu cơ bản
như : int, double hoặc các kiểu dữ liệu có cấu trúc như : struct, class. Ví dụ minh
họa dùng kiểu int.

Max_size là kích thước tối đa của stack, ở đây chỉ cho là 10 để minh họa được
phương thức is_full().
Phần code là hoàn toàn đơn giản vì chỉ minh họa thao tác của stack và cách cài đặt
stack trên C++. Tuy nhiên nhóm thấy rằng các trương trình ở đây chưa cần thết
phải dùng đến C++.

3 Ứng dụng
3.1 Phát bểu bài toán ứng dụng

Lập trình trương trình mô phỏng máy tính điện tử “CASIO fx 570” với giao diện
đồ họa, thao tác chuột và bàn phím với các chức năng sau:
(Trước khi làm trương trình này nhóm đã tìm hiểu khá kỹ về máy tính điện tử)

1. Tính toán biểu thức bất kì gồm các phép toán: (trong chế độ COMP)
1. + - * / (-) ^ !
2. x , x , e , 10 , x
3. Sin, cos, tan, ln, log10, abs, rand, %, eng
4. nCr (tổ hợp), nPr (chỉnh hợp), Dx (đạo hàm), Sx (tích phân)
5. M+, M- : số nhớ tăng và giảm trong các phép cộng trừ
2. Tính toán trên miền phức: nhập và tính toán +, -, *, /(trong chế độ
COMPLEX)
3. Chuyển đổi giữa các cơ số: DEC, HEX, BIN, OCT và tính toán trên đó
(chế độ BASE-N)
4. Giải phương trình và hệ phương trình (chế độ EQN) (EQuatioN)
1. Phương trình bậc 2 và bậc 3
2. Hệ phương trình bậc 2 và bậc 3
3. Hệ phương trình tuyến tính bậc cao (có thể vài trục phương trình)
nhưng sẽ chuyển từ chế độ đồ họa văn bản để tính toán; tính
song quay lại chế độ đồ họa.
5. Tính toán ma trận (chế độ MATRIX): chưa được bổ xung vì thấy các

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 38

phép tính gần giống giải hệ PT tuyến tính.


6. Một số khả năng tính toán
1. Cho phép lưu các phép tính đã tính và quay lại các phép tính đó
(History).
2. Cho phép dùng nút DEL để sửa phép tính nhập sai.
3. Cho phép thiết lập các chế độ để tính toán:
1. FIX : làm tròn số và lấy bao nhiêu số sau dấu phẩy
(0 9)
2. SCI :quy cách viết số theo lũy thừa của 10 đồng thời
lấy bao nhiêu số sau dấu phẩy (0 9)
3. DEG :tính toán ở chế độ Decimal
4. RAD :tính toán ở chế đọ Radian
5. NORM :chuyển sang chế độ tính toán bình thường
(Normal)
4. Cho phép chuyển đổi giữa ba cách viết số: thập phân phân số
hỗn số.
5. Cho phép lưu các giá trị cần lưu vào các biến nhớ: A, B, C, D, E,
F, X, Y cũng như M. Có thể nhận biết là lưu số bình thường hay
lưu dạng số phức.
6. Cho phép thực hiện các chức năng bộ nhớ:
1. Xóa toàn bộ bộ nhớ. và thiết lập các chế độ máy tính về
trạng thái ban đầu
2. Reset các chế độ máy tính về trạng thái ban đầu
3. Và cả hai thao tác trên
7. Khả năng nhận biết thông minh các phím được ấn và tác động khi
ấn một phím bất kì và thể hiện sự thay đổi đó lên màn hình.(đặc
biệt là các phím chức năng như: phím SHIFT, ALPHA, STO,
MODE) và các phím có nhiều chức năng. (chú ý một phím có thể
có nhiều chức năng khác nhau)
8. Các thao tác sử lý phím ANS (phím lưu giữ kêt quả phép tính gần
nhất) là khá hay (giống như máy tính thật).
7. Các chức năng về đồ họa
1. Cho phép dùng cả chuột lẫn bàn phím
2. Giao diện thân thiện và đẹp:

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 39

1. Các nút phím thiết kế nổi


2. Có 9 giao diện để lựa chọn
3. Các công cụ được thiết kế trượt chứa các Menu và các
Radio Button
4. … và còn nhiều …được nói rõ hơn trong file word hướng
dẫn ở thư mục Calculator.

Giao diện trương trình


(chú ý nên dùng PC để chạy trương trình này vì các laptop thường không hiện đầy đủ chữ đồ họa)

Hình 14: giao diện trương trình chính

3.2 Mô tả, đánh giá độ phức tạp của giải thuật

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 40

Vì bài trương trình này chứa nhiều bài toán con khác nhau nên ta xem xét độ phức
tạp của từng bài toán: ví dụ:
Độ phức tạp của phần tính toán biểu thức là độ phức tạp của bài toán Balan (đã xét
ở trên) Æ O(n), với n là độ dài của xâu nhập vào.
Các thao tác: cộng ma trận là O(n); nhân ma trận là O( )
Độ phức tạp của bài toán giải phương trình tuyến tính là O( ) vì: ở đây dùng
phương pháp tính DET với thời gian tính O( ).
¾ Ta chỉ có thể đánh giá được thời gian tính của từng giải thuật trong trương
trình mà không có thời gian tính cho cả trương trình này.

3.3 Mô tả cài đặt trương trình

Bài toán được chia ra từng phần nhỏ :


• Xử lý giao diện : Hiến (trưởng nhóm) làm
• Tính toán biểu thức trong chế độ COMP(chế độ thường) : Tùng làm
• Tính toán biểu thức trong chế độ COMPLEX : Minh làm
• Giải các loại phương trình và hệ PT: Phương làm
• Chế độ BASE-N: Thanh Tùng làm
• Tổng hợp lại : trưởng nhóm kết hợp với tất cả thành viên hợp tác

Một số vấn đề mới được đặt ra


• Sử lý chuột kết hợp bàn phím và tương tác giữa các bộ phận
• Thao tác với các phím, mỗi phím có nhiều chức năng và có ảnh hưởng lẫn
nhau khi ta gõ 1 phím bất kì( trạng thái làm việc phải được đưa lên màn hình
trạng thái)
• Vấn đề tính toán số phức và số thực phải sử lý xâu rất nhiều
• Vấn đề giải PT bậc 3 hệ PT tuyến tính và tính toán ma trận
• Vấn đề làm tròn số(FIX,SCI) và chuyển đổi một số thực Æ phân số hay hỗn
số
• Vấn đề thao tác với các biến nhớ.
• Vấn đề liên kết các trương trình nhỏ thành trương trình lớn
• ……

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 41

Giải quyết vấn đề (theo phương pháp chí để trị!)


• Trước tiên phải vẽ được giao diện rõ ràng
• Quy định xác định các tọa độ và quy định các phím PC tương ứng với các
phím Calculator và dùng các ngắt chuột để thực hiên các thao tác Click
• Mỗi phím sẽ là một hàm riêng
• Xây dựng từng module nhỏ, cho chạy độc lập và kiểm tra đúng đắn trước
khi gép vào trương trình lớn
• Vấn đề tổng hợp sẽ dễ dàng nếu có những quy định chung được thống nhất
như: biến, hàm: đầu vào, đầu ra; đặc biệt cần trao đổi thường xuyên
• Khi đã tổng hợp xong tất cả cùng chạy thử và tìm những lỗi khó phát hiện.
(việc gỡ lỗi được tiến hành liên tục trong suốt quá trình làm, và là một quá
trình tinh chỉnh dần dần).
• ….

Mặc dù bài tập này viết về stack nhưng phần lớn code là về các phần sử lý khác.
Tuy nhiên bản chất stack chỉ là một cơ cấu rất đơn giản, chính vì đơn giản nên ta
khó thấy được ứng dụng thực tế của nó. Là cơ cấu đơn giản nên stack thường đóng
vai trò trung gian trong các giải thuật mà điển hình là cơ cấu cho các bài toán đệ
quy; nhở đó ta có thể dùng phương pháp khử đệ quy để tối ưu hóa trương trình về
mặt tốc độ. (các trương trình dịch dùng stack chứa các kết quả trong đệ quy thì khi
ta muốn khử đệ quy thì lại dùng stack). Bản chất nó là ngược nhau.

Sau đây là một số ví dụ để kiểm thử trương trình: (quan trọng)

3.4 Ví dụ minh họa và hướng dẫn sử dụng

Chạy trương trình CALC.C (cần có file EGAVGA.BGI)


Vào giao diện Graphics, click phím ON để chạy.
Các phím phím ẩn(chữ nhở phía trên) phải dùng phím SHIFT hoặc ALPHA cùng
mới có hiệu lực. vd SHIFT và SIN tương đương ARCSIN
Chú ý: màu vàng tượng trưng cho shiftl màu đỏ tượng trưng cho alpha

VD1: + - * /
Phía trên màn hình tính toán có 3 chữ: COMP DEC NORM tượng trương cho chế

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 42

độ hiện hành
COMP(computing) DEC(decimal) NORM (normal)
Dùng chuột hoặc bàn phím gõ:
• 10 / 3 Enter với phím

• 10 ÷ 3= với chuột (‘÷’ lấy trong bảng mã mở rộng ASCII)

ÆKết quả ra 3.3333…


Gõ tiếp
• -3=

ÆKết quả ra 0.3333.. (chú ý dòng chữ ANS tượng trưng cho kết quả phép tính trước)
Gõ phím S<->D cho ra kết quả 1/3, gõ lần nữa cho kết quả 0.3333..
Gõ 2 phím
• SHIFT và S<->D

ÆCho kết quả là hỗn số(nếu là phân số >1)


Phía trên màn hình tính toán bây giờ có thêm một mũi tên nhỏ báo hiệu trong bộ nhớ
máy tính đã lưu lại phép tính trước đó. Click vào nút gần chữ History để xem.(cấu trúc
lưu trữ cho history là DSLK kép). Nếu đã có những phép tính được tính trong quá khứ
ta có thể xem lại bằng phím mũi tên phía phải dưới, sau đó có thể quay lại
Phím ON có thể xóa History
Sau mỗi VD gõ AC để bắt đầu tính
VD2: căn và lưu biến nhớ
Gõ 3 phím: (tính căn bậc 2)
• √ 9 =

Æra 3
Gõ 4 phím (tính căn bậc n)
• 4 √ 16 =

Æra 2
Gõ 3 phím
• SHIFT RLC/STO A ( A tượng trưng cho phím có chữ A màu đỏ)

Ægiá trị 2 đã được gán cho biến A


Gõ phím AC sau đó gõ 2 phím
• CLR A

Æhiển thị giá trị vừa lưu và ta có thể tính toán với giá trị A bằng cách gõ 2 phím:
• ALPHA A

VD: gõ ALPHA A + 3 - ALPHA A

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 43

Æđáp số là 3.
Tương tự cho các biến nhớ khác.
Giá trị các biến này giữ nguyên cho đến khi xóa nó(CLEAR) hoặc thay bằng giá trị
khác.

VD3: SIN COS TAN …LN ABS …


Gõ 6 phím
• Sin ( PI ÷ 2 =

Æra 1
Gõ 4 phím
• SHIFT SIN 1 =

Æra PI/2
Gõ 6 phím
• Ln ( e ^ 2 =

Æra 2
Các hàm khác tương tự…

VD4: phép cộng gộp M+


Gõ 6 phím
• 1 M+ 2 M+ 3 M+

Ætổng của 3 số đã được lưu vào biến M


Tương tự 2 phím
• SHIFT M+ thành M-

VD5: chuyển sang chế độ phức


Chý ý: phí trên dòng chữ COMP Æ CMPLX
Nhấn MODE và chọn COMPLEX
Gõ các phím
• ( 1 + i ) * ( 1 - i )

ÆKết quả 2
Chú ý : chế độ phức chỉ hỗ trợ 4 phép tính cơ bản và phép trừ 1 ngôi
VD6 : chuyể sang chế độ giải hệ phương trình
Nhấn MODE và chọn EQN
Chọn một trong 5 chế độ
Phương trình bậc 2
PT bậc 3

Hệ phương trình bậc 2

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 44

HPT bậc 3
Hệ phương trình tuyến tính bậc cao

Vd Chọn 4 để giải PT bậc 3


Nhập theo hướng dẫn để giải PT bậc 3 bất kì
Vd : a=1 b=-6 c=11 d=-6
Æx1=1 x2= 3 x3= 2
VD6: các chế độ hiển thị giá trị FIX SCI
Nhấn
• SHIFT MODE

Sau đó chọn một trong 5 lựa chọn


1. NORM - chế độ thường

2. DEG - chế độ decimal

3. RAD - chế độ radian

4. FIX - chế độ định dạng số chữ số sau dấu phẩy

5. SCI - chế độ viết quy cách theo lũy thừa của 10

VD7 : xóa bộ nhớ


Nhấn 2 phím
• SHIFT 9

Chọn 3 chế độ
Memory Setup All
Trong đó Memory là xóa bộ nhớ vd các biến A,B,C…cho cả số phức lẫn số thực
Setup là xóa các chế độ thiết lập vd FIX,SCI, MODE…
ALL là xóa toàn bộ, đưa máy về trạng thái ban đầu
VD8: phím DEL
Gõ như sau
• (2+4)+(4+2

Sau đó gõ phím DEL 5 lần; sau đó gõ tiếp


• -(4+2=

Æra 0
Vd nữa

• 2 / Tan ( pi / 2

Sau đó gõ phím DEL 5 lần; sau đó gõ tiếp

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa
SSTTAACCKK AAD
DTT Trang 45

• Sin ( pi / 2

Æra 2

VD9: một số tiện ích


Click vào phím nhỏ gần chữ Options và chọn các giao diện
Kéo chuột ra phía lề trái Æ có một menu popup hiện lên, chọn add CLOCK để xem
ngày giờ hệ thống. có thể tắt đồng hồ đi bằng cách làm lại.
VD10: tắt máy và thoát khỏi trương trình
Tắt máy: SHIFT AC
Sau khi khởi động lại bằng ON thì bộ nhớ lúc trước khi tắt không bị mất.
Thoát: click vào dấu nhân phía trên trái

Tất cả các ví dụ ở trên là rất đơn giản

4 Kết luận

Sau khi bốc thăm chủ đề một cách công bằng và trung thực, nhiều bạn cho rằng
chúng em gặp may và rằng Stack ADT là một chủ đề quá dễ(quả thật cũng may !).
Mới đầu chúng em cũng chỉ biết Stacks là một cấu trúc theo kiểu LIFO (Last – In –
First – Out); còn về mặt ứng dụng thì chỉ biết cài đặt một số trương trình đơn giản
theo kiểu mô phỏng hoạt động của Stacks…(chỉ đến vài trục dòng code). Với
quyết tâm xây dựng được những trương trình lớn hoàn chỉnh có ứng dụng Stacks
cùng với quá trình tìm tòi sách vở, chúng em nhận ra “Stacks quả thật là kì diệu”.

Bài tập lớn môn cấu trúc dữ liệu và giải thuật Giáo viên hướng dẫn : Nguyễn Đức Nghĩa

You might also like