Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 1
Cấutrúcdữ liệuvàGiảithuật
Chương III:
Stack và Queue
Danh sách kiểungănxếp - Stack
– Stack
z Mộtkiểudanhsáchtuyến tính đặc
biệt
z Phép bổ sung và phép loạibỏ tuân
thủ theo cơ chế “vào sau ra trước”
(last in first out) , đượcthựchiện ở
đầu đỉnh
đỉnh
đáy
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 2
Danh sách kiểungănxếp - Stack
– Hai thao tác cơ bản đốivới danh sách kiểungăn
xếp
z push(Element e) : bổ sung phầntử vào Stack
z Element pop(): Loạibỏ và trả ra giá trị củaphầntửở
đỉnh Stack
– Các thao tác khác
z Int size(): Trả ra số các phầntử trong Stack
z Boolean isEmpty(): KiểmtraxemStack córỗng không
z Element top(): Trả ra giá trị củaphầntửởđỉnh Stack
Các thao tác cơ bảncủa Stack
Top
Stack
Top
Push
Data
Stack
Top
Đẩymộtphầntử
vào stack
Stack
Overflow
Data
Trường hợpStack đầy
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 3
Các thao tác cơ bảncủa Stack
Pop
Top
Stack
Top
Stack
Data
Lấyraphầntửởđỉnh
stack
Top
Stack
Underflow
Trường hợp Stack cạn
Danh sách kiểungănxếp
[9,8,7]3size()
[9,8,7]-push(7)
[9,8]-push(8)
[9]-push(9)
[]trueisEmpty()
[]5pop()
[5]7pop()
[5,7]7top()
[5,7]-push(7)
[5]3pop()
[5,3]-push(3)
[5]-push(5)
[ ]-create()
StackOutputThao tác
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 4
Ứng dụng củaStack
– Lưutrữ các trang web đãtừng được duyệttrên
Web browser
– Cài đặt thao tác Undo trong các phầnmềmsoạn
thảo
– Lưudanhsáchcáclờigọi hàm trong Java Virtual
Machine
Lưutrữ kế tiếpcủa Stack
z Stack có thểđượclưutrữ bởimộtvector lưutrữ S, gồmn
ô nhớ kế tiếp nhau
z Đỉnh stack đượcxácđịnh bởimộtchỉ số T
– T sẽ đượccậpnhậtnếucóthaotácbổ sung hay loạibỏ
đượcthựchiệntrênstack
S
123
t
…
N
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 5
Lưutrữ kế tiếpcủa Stack
z Giảithuậtbổ sung mộtphầntử vào Stack đượclưutrữ kế
tiếp
Procedure PUSH(S,T,X)
Begin
{S: vector lưutrữ có n ô nhớ; T: chỉ số củaphầntửđỉnh stack
hiệnthời; X là giá trị cần thêm vào }
1. if T >= n then begin
write(‘STACK TRÀN’);
return;
end;
2. T:= T+1;
S[T] := X;
End
Lưutrữ kế tiếpcủa Stack
z Giảithuậtlấyraphầntửởđỉnh củaStack đượclưutrữ
kế tiếp
Procedure POP(S,T, Y)
Begin
{S: stack đang xét ; T: chỉ số củaphẩntử tại đỉnh stack hiệnthời;
Phầntửđượclấyrasẽđượcbảolưusử dụng biếnY }
1. if T = 0 then begin
write(‘STACK CẠN’); return;
end;
2. Y:= S[T];
S[T] := null;
T:= T-1;
End
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 6
Hiệunăng và Hạnchế
z Hiệunăng
– n là số phầntử củastack
– Không gian lưutrữ : O(n)
– Cácthaotáccơ bảncóđộ phứctạpO(1)
z Hạnchế
– Kích thướctối đaphải đượcxácđịnh trướcvà
không được thay đổi
– Xảyratrànstack
Lưutrữ móc nối đốivới Stack
– Cách tiếpcận1
z Đỉnh của Stack được coi là phầntử nằm ởđầu danh sách
z pop() : Lấyraphầntửđầu tiên trong danh sách móc nối
z push(o) : Bổ sung mộtphầntử vào đầudanhsáchmócnối
Đỉnh Stack
L
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 7
Lưutrữ móc nối đốivới Stack
Đỉnh Stack
L
•Cáchtiếpcận2
•Phầntử cuối cùng đượccoilàđỉnh stack
•pop() : Lấyraphầntử cuối cùng trong danh sách móc nối
•push(o): Bổ sung mộtphầntử vào cuối danh sách móc nối
zCách lưutrữ móc nối nào phù hợphơn đốivớicấutrúcdữ liệu Stack?
Lưutrữ móc nối đốivới Stack
– Khai báo Stack móc nối trong C
struct stacknode {
int item;
struct stacknode *next;
} ;
typedef struct stacknode STACKNODE;
typedef STACKNODE * STACKNODEPTR;
STACKNODEPTR top = NULL;
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 8
Lưutrữ móc nối đốivới Stack
– Bổ sung vào Stack
int push ( STACKNODEPTR *top , int value ) {
STACKNODEPTR newnode;
newnode = malloc sizeof (STACKNODE);
if (nut == null) { printf(“\n No memory”); return 1; }
else {
newnode->item = value;
newnode ->next = *top;
*top = newnode;
return 0;
}
}
Lưutrữ móc nối đốivới Stack
– Loạibỏ nút
int pop ( STACKNODEPTR *top) {
int item; STACKNODEPTR temp;
temp = *top;
item = (*top)->item;
*top = (*top)->next;
free (temp);
return item;
}
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 9
Danh sách kiểuhàngđợi-Queue
z Queue
z Queue (Hàng đợi) là mộtkiểu
danh sách tuyến tính đặcbiệt
z Phép bổ sung và loạibỏ hoạt
động theo cơ chế “vào trước
ra trước” (first in first out) ; bổ
sung ở một đầuthìloạibỏở
đầukia
lốisau
lối
trước
Danh sách kiểuhàngđợi-Queue
– Hai hàm cơ bản đốivới danh sách kiểuhàngđợi
z enqueue(Element e)
z Element dequeue()
– Các hàm khác
z create():
z size() :
z isEmpty():
z Element front()
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 10
Danh sách kiểuhàngđợi–Queue
[9,8,7]3size()
[9,8,7]-enqueue(7)
[9,8]-enqueue(8)
[9]-enqueue(9)
[]trueisEmpty()
[]7dequeue()
[7]3dequeue()
[3,7]3front()
[3,7]-enqueue(7)
[3]5dequeue()
[5,3]-enqueue(3)
[5]-enqueue(5)
[ ]-create()
QueueOutputThao tác
Ứng dụng củaQueue
– Hàng đợi trong các phòng bán vé
– Truy nhập vào các thiếtbị dùng chung tạivăn
phòng (ví dụ máy in)
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 11
Lưutrữ kế tiếp đốivớiQueue
– Sử dụng mộtvector lưutrữ Q gồmn ô nhớ kế tiếpnhauđể
biểudiễnmột Queue
– Cầnnắm được hai chỉ số
R: Chỉ số củaphầntử nằm ở lốisaucủaQ
F: Chỉ số củaphầntửởlốitrướccủaQ
Q
1
23 rf
Lưutrữ kế tiếp đốivớiQueue
z Khi Queue rỗng thì F = R = 0
z Khi bổ sung thêm mộtphầntử vào Queue thì R tăng lên 1
z Khi lấyramộtphầntử trong Queue thì F tăng lên 1
z Nhược điểmcủacáchtổ chứclưutrữ này
– Các phầntử trong Queue sẽ dịch chuyểnkhắpkhônggiannhớ
nếuliêntụcthựchiệnbổ sung rồiloạibỏ
– Hiệntượng TRÀN vẫnxảy ra khi vector lưutrữ Q vẫncònchỗ
nhưng R = n
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 12
Lưutrữ kế tiếp đốivớiQueue
z Khắcphụccácvấn đề bằng cách coi vector lưutrữ
Queue đượctổ chứcdướidạng vòng
– Q[1] được coi nhưđứng sau Q[n]
F
R
Q[1]
Q[2]
Q[3]
Q[n]
Q
123 fr
Các thao tác cơ bảncủa Queue
Queue
Enqueue
D
Data
A B
front
rear
A B D
front
rear
Queue
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 13
Các thao tác cơ bảncủa Queue
Queue
Dequeue
A
Data
B D
front
rear
A B D
front
rear
Queue
Lưutrữ kế tiếp đốivớiQueue
z Giảithuậtbổ sung vào Queue đượclưutrữ trong vector Q
gồmn phầntử và đượctổ chứcdướidạng thường
Procedure ENQUEUE(Q,F,R,X)
Begin
1. if (R >= n) then begin
write(‘QUEUE TRÀN’);
return;
end;
2. {Q rỗng} if F = 0 then F:= R:= 1;
3. else R:= R+ 1;
4. Q[R] := X;
End
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 14
Lưutrữ kế tiếp đốivớiQueue
z Giảithuậtlấyra(loạibỏ ) khỏi Queue
Procedure DEQUEUE(Q,F,R, Y)
Begin
{ Y là biếnlưutrữ phầntửđượclấyra}
1. if F = 0 then begin
write(‘QUEUE CẠN’);
return;
end;
2. Y:= Q[F]; {lưu giá trị củaphầntử cầnlấy}
3. if F = R=1 then F:= R:= 0; { Queue chỉ còn mộtphầntử}
4. else F:= F+ 1;
End
Lưutrữ kế tiếp đốivớiQueue
z Bài tập: Hãy viếtgiảithuậtthựchiệnbổ sung và loạibỏ
trên Queue lưutrữ kế tiếpdướidạng vòng
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 15
Lưutrữ móc nối đốivới Queue
– Cách tiếpcận1: Sử dụng danh sách nối đơn
z Lốitrướccủa Queue là đầu danh sách
z enqueue(o): bổ sung phầntử vào cuối danh sách
z dequeue() : loạibỏ phầntửởđầu danh sách
z Luôn nắmgiữ hai con trỏ F trỏ tớiphầntửởlốitrước
của queue, R trỏ tớiphầntửởlốisaucủa queue
Lối sau của
Queue
L
R
F
Lốitrước
của Queue
Lưutrữ móc nối đốivới Queue
– Cách tiếpcận2:
z Lốisaucủa Queue là đầu danh sách
z enqueue(o): bổ sung phầntử vào đầu danh sách
z dequeue() : loạibỏ phầntửởcuối danh sách
Lối trước của
Queue
L
F
R
Lốisau
của Queue
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 16
Lưutrữ móc nối đốivới Queue
z Giảithuậtbổ sung mộtphầntử vào Queue lưutrữ trong
danh sách móc nối–Bổ sung vào cuối danh sách
Procedure ENQUEUE(F,R,X)
Begin
1. {Khởitạo nút mới} Call New(p);
INFO(p) := X; LINK(p) := Null;
2. {Danh sách đã cho rỗng} if F = Null then F:= R:= p;
3. else LINK(R) := p; R:= p;
End
Lưutrữ móc nối đốivới Queue
z Giảithuậtloạibỏ phầntử khỏi Queue – Loạibỏ phầntử
đầu tiên trong danh sách
Procedure DEQUEUE(F,R, Y)
Begin
{ Y là biếnlưutrữ phầntửđượclấyra}
1. p:= F; Y:= INFO(p);
2. {Danh sách ban đầuchỉ có mộtphầntử}
if (F = R) and (F <> Null) then F:= R:= Null;
2. else F:= LINK(p);
3. Call Dispose(p) ;
End
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 17
Hàng đợihaiđầu-DEQueue
z DeQueue
– Hàng đợi hai đầulàmộtcấutrúcdữ liệudạng hàng đợi
nhưng nó hỗ trợ phép bổ sung và loạibỏởcảđầuvàcuối
z Các hàm cơ sở củahàngđợi hai đầuD
– insertFirst(o)
– insertLast(o) :
– removeFirst()
– removeLast()
z Các hàm khác
– first()
– last()
– size()
– isEmpty()
– create()
Hàng đợihaiđầu-DeQueue
[8,9,7]3size()
[8,9,7]-insertLast(7)
[8,9]-insertFirst(8)
[9]-insertLast(9)
[]trueisEmpty()
[]errorremoveLast()
[]7removeLast()
[7]3removeFirst()
[5,7]-insertLast(7)
[5]3removeFirst()
[3,5]-insertFirst(3)
[5]-insertFirst(5)
[ ]-create()
DeQueueOutputThao tác
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 18
Lưutrữ móc nốivới DeQueue
z DeQueue đượclưutrữ sử dụng cấu trúc danh sách
móc nối kép (Doubly Linked – List)
– Mỗi nút trong danh sách ngoài trường INFO chứadữ
liệucòncó2 trường con trỏ
z PREV
z NEXT
– Cầnnắm được hai con trỏ, con trỏ L trỏ tớinútcực
trái, con trỏ R trỏ tới nút cựcphảicủa danh sách
– Với danh sách rỗng , L = R = NULL
L
BCGH
R
Lưutrữ móc nối đốivới DeQueue
z Giảithuậtbổ sung phầntử vào đầumột DeQueue lưu
trữ trong một danh sách nốikép
z Giảithuậtloạibỏ phầntửđầumột DeQueue lưutrữ
trong mộtdanhsáchnốikép
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 19
Bài toán đổisố cơ số
– Bài toán: Viếtmộtsố trong hệ thập phân thành số
trong hệ cơ số b bấtkỳ
z Ví dụ:
– (356)
10
= (101100100)
2
– (356)
10
= (544)
8
– (356)
10
= (164)
16
Bài toán đổicơ số sử dụng Stack
z Ví dụ:
– (356)
10
= (101100100)
2
356
178
89
44
22
11
5
2
1
2
2
2
2
2
2
2
2
2
0
1
0
1
1
0
0
1
0
0
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 20
Bài toán đổicơ số sử dụng Stack
– Thuật toán:
z Đầu vào: Số n trong hệ thậpphân
z Đầura: Số tương ứng với n trong hệđếmcơ số b
z Thựchiện
1. Lấychữ số tạobởin%b. ĐẩyvàoStack
2. Thay n bằng n/b để tiếptụclấycácchữ số tiếp theo trong
kếtquả
3. Lặplạibước 1 và 2 cho đếnkhikếtquả của phép chia là
0
4. Lầnlượtlấycácchữ số ra khỏi Stack và in chúng ra kết
quả
Bài toán đổicơ số sử dụng Stack
4
6
4
4
6
1
n= 356
Empty stack
n%16 = 4
n = n/16 = 22
n%16 = 6
n = n/16 = 1
n%16 = 1
n = n/16 = 0
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 21
Bài toán đổicơ số sử dụng Stack
Procedure CONVERT(n, b)
Begin
1. m = N;
2. { Tính số dư và nạp vào stack S}
while m <> 0 do begin
R := m mod b; call PUSH(S, T, R);
m := m div b; {thay m bằng thương của phép chia m cho b}
end;
3. {Hiệnthị từng chữ số nhị phân trong mã số biểudiễnN}
while T <> 0 do begin call POP(S,T,X); {lấysố ra khỏi stack} write(X);
end
End
Bài toán kiểmtracặpngoặc
– Kiểmtracặp ngoặc
Mỗidấu “(”, “{”, or “[” đềuphảicómộtdấu đóng tương ứng
“)”, “}”, or “[”
z Đúng: ( )(( )){([( )])}
z Đúng : ((( )(( )){([( )])}
z Sai: )(( )){([( )])}
z Sai: ({[ ])}
z Sai: (
– Viếtgiảithuậtnhậnmộtxâuđầuvàogồmcácký
tự mở , đóng ngoặc. Kiểmtraxâucóhợplệ
không
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 22
Function ParenMatch(X,n):
{ X là mộtxâubaogồm n ký tự mở, đóng ngoặc. Giảithuậttrả ra giá trị true nếuxâuX
chứamộtsố hợplệ cặp ngoặc, nếu không trả ra giá trị false}
KhởitạoS làmộtstack rỗng
for i =1 to n do begin
if X[i] là mộtngoặcmở then
S.push(X[i])
else if X[i] là một ngoặc đóng then begin
if S.isEmpty() then
return false {không có ngoặ
cmở tương ứng}
if S.pop() không hợpkiểuvới X[i] then
return false {cặp ngoặc đóng mở khác kiểu}
end
end
if S.isEmpty() then
return true { tấtcả cặp ngoặchợplệ}
else
return false {vẫntồntạimộtsố ngoặcmở mà không tìm thấy ngoặc đóng tương ứng}
Biểuthứcsố họcvới ký pháp Balan
z Thông thường, mộtbiểuthứcsố học đượcbiểudiễn theo
ký pháp trung tố (infix notation)
– Dấu phép toán (toán tử) nằmgiữa 2 toán hạng
z A+B*C
– Thứ tự thựchiện các phép toán đượcxácđịnh sử dụng các
cặpdấungoặchoặcquyđịnh mộtthứ tựưutiêngiữacác
phép toán
z Biểuthức A* B^2 – C/D + E đượcthựchiện theo thứ tự
sau
B^2 Æ A*(B^2)ÆC/DÆ (A*(B^2)) –(C/D)Æ ((A*(B^2)) –
(C/D)) + E
– Tính toán giá trị biểuthứcsẽ khá phứctạp
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 23
Biểuthứcsố họcvới ký pháp Balan
z Có thể biểudiễncácbiểuthức mà không dùng đếndấu
ngoặcsử dụng ký pháp tiềntố (prefix notation) hoặcký
pháp hậutố (postfix notation)
z Biểuthứcdạng tiềntố và hậutố
– Trong ký pháp dạng tiềntố: Toán tử luôn được đặttrước
2 toán hạng
– Trong ký pháp dạng hậutố: Toán tử luôn đặt sau 2 toán
hạng
Toán tử
Toán hạng 1
Toán hạng 2
Toán hạng 1
Toán hạng 2
Toán tử
Biểuthứcsố họcvới ký pháp Balan
A B C/ + D + A / B C DA + B / C – D
A B + C D - // + A B – C D(A + B ) / (C-D)
A B C * + + A * B CA + B* C
A B + C ** + A B C (A+B) * C
A B ++ A BA+B
Dạng hậutốDạng tiềntốDạng trung tố
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 24
Bài toán tính giá trị củabiểuthứcdạng hậutố
z Tính giá trị củamộtbiểuthứcdạng hậutố sử dụng Stack
– Đầuvào: Xâukýtự biểudiễnbiểuthứcdạng hậutố
z A B + C – D E * /
z Các giá trị của các biếnsố
z Các bước chính trong giảithuật
– Đọcbiểuthứcdạng hậutố từ trái qua phải
– Nếukýtự được đọclàmột toán hạng thì lưugiátrị vào stack
– Nếukýtự được đọclàmột toán tử X thì lầnlượtlấytừ stack
ra 2 giá trị, thựchiệnphéptoánX với2 giátrịđó, nạpkết
quả vào stack
– Thựchiệncácbướctrênđến khi toàn bộ biểuthức đã được
đọc
Bài toán tính giá trị củabiểuthứcdạng hậutố
Procedure EVALUATE (P, VAL)
Begin { P là biểuthứcdạng hậutố cần tính, VAL là biếnsẽ lưugiátrị tính được}
1. Ghi thêm dấu‘)’vàocuốiP để đánh dấu điểmkếtthúc
2. repeat
Đọckýtự X trong P (lầnlượttừ trái sang phải) ;
if X là mộttoánhạng then call PUSH(S, T, X) ;
else begin
call POP(S, T, Y) ; call POP(S, T, Z);
Thựchiệnphéptoánvới hai toán hạng Z,Y kếtquả là W;
call PUSH (S, T, W) ;
end;
until Gặpdấukết thúc xâu ‘)’ ;
3. call POP (S,T, VAL);
End
Cấu trúc dữ liệu và Giải thuật
Đỗ Bích Diệp - Khoa CNTT - ĐHBK Hà
nội 25
Bài toán tính giá trị củabiểuthứcdạng hậutố
z Ví dụ: A B + C – D E * / với A = 5, B = 14, C = 1, D = 2, E = 3
318181818191955
622114
3
/
18/6
*
2*3
ED-
19-1
C+
5+14
BA
Ký tự
được đọc
Stack
VAL
Chuyểnbiểuthứcdạng trung tố sang dạng hậutố
– Bài toán
z Xét biểuthứcsố họcdạng trung tố gồm các phép toán
cộng, trừ, nhân, chia, lũythừa và các dấungoặc
z Viếtbiểuthứcdạng hậutố tương ứng vớibiểuthức
trung tốđầuvào
– Để thựchiện, trong biểuthức trung tố cầnbiết
z Thứ tựưutiêncủa các phép toán : Lũythừa Æ Nhân,
Chia Æ Cộng, Trừ
z Qui tắckếthợp: Nếu có hai phép toán cùng thứ tựưu
tiên
– Lũythừa: Phảitrước, trái sau. 2^3^4 = 2^(3^4)
– Các phép toán khác : Trái trước, phảisau
z Dầungoặc: Ưutiênnhất