Stack & Queue
ThS. Nguyễn Hà Giang Hutech - IT
Nguyen Ha Giang 2009
2
Giới thiệu
• LIFO: Last In First Out • Thao tác Pop, Push chỉ diễn ra ở 1 đầu
Nguyen Ha Giang 2009
3
Hiện thực stack
Mảng 1 chiều
Danh sách LK
Cấp phát động!
Kích thước stack khi quá thiếu, lúc quá thừa
Push/Pop khá dễ dàng
Push / Pop hơi phức tạp
Nguyen Ha Giang 2009
4
Khai báo
• Tạo cấu trúc Node cho stack
typedef struct node {
info; DataType struct node * next;
}NODE; typedef NODE * NodePtr;
pTop quản lý stack
pTop;
NodePtr pTop = NULL;
Khởi tạo stack
Nguyen Ha Giang 2009
5
Thao tác
• Các thao tác trên stack
Pop
InitStack
Push
IsEmpty
GetSize
Top
pTop
Đầu danh sách
Nguyen Ha Giang 2009
6
Pop
• Pop:
– Lấy ra phần tử đầu danh sách – Trả về nội dung và giải phóng nút
pTop
pTop
Pop
5
2
9
2
9
Nguyen Ha Giang 2009
7
Pop
int Pop(NodePtr &pTop) { NodePtr p; value; int if (pTop == NULL) {
printf(“Stack is empty!”); return -1;
} p = pTop; pTop = pTop->next; value = p->info; FreeNode(p); return value;
}
Nguyen Ha Giang 2009
8
Push
• Push
– Tạo Node mới – Đưa vào đầu stack
pTop
pTop
Push
new
2
9
8
2
9
Nguyen Ha Giang 2009
9
Push
void Push(NodePtr &pTop, int x) {
NodePtr node; node = NewNode(); node->info = x; node->next = pTop; pTop = node;
}
Nguyen Ha Giang 2009
10
Top
• Top:
– Xem nội dung của phần tử đầu stack
pTop
Top
5
2
9
pTop
5
2
9
Nguyen Ha Giang 2009
11
Top
int Top(NodePtr pTop) {
int value; if (pTop == NULL) {
printf(“Stack is empty!”); return -1;
} value = pTop->info; return value;
}
Nguyen Ha Giang 2009
12
ứng dụng
• Ứng dụng stack – Khử đệ quy:
• Tháp Hanoi, QuickSort…
– Áp dụng cho các bài toán dùng mô hình LIFO
Nguyen Ha Giang 2009
13
Tháp Hanoi
Move( số đĩa, cọc nguồn, cọc đích, cọc tạm)
• Tháp Hanoi
1
2
3
1
2
3
1
2
3
Move(n-1, 1, 3, 2);
Kết quả
Move(1, 1, 2, 3);
Move(n-1, 3, 2, 1);
1
2
3
1
2
3
Nguyen Ha Giang 2009
14
Tháp Hanoi
• Stack khử đệ quy
{n, src, des}
Stack lưu trữ thứ tự ngược
• • Các cọc đánh số 1, 2, 3 • Cọc temp = 6 – (src+des) 1. Push stack : {n, 1, 2} 2. Pop: Stack {n, src, des) • Nếu n =1: move src des • Ngược lại:
Nguyen Ha Giang 2009
15
– temp = 6 – (src+des) – Push stack : {n-1, temp, des} – Push stack : {1,src, des} – Push stack : {n-1,src, temp}
Tháp Hanoi
• Bài tập: Chương trình tháp Hanoi – Không đệ quy, dùng stack khử – Sử dụng dslk cho stack
Nguyen Ha Giang 2009
16
QuickSort
• Ý tưởng QuickSort ko đệ quy
– Dùng stack khử đệ quy – Stack lưu giữ {biên trái, biên phải} của đoạn – Khi phân đến [left, right] ta được • [left, i] các phần tử nhỏ hơn x • [i+1,j-1] các phần tử bằng x • [j, right] các phần tử lớn hơn x – Đưa vào stack đoạn bên phải – Nếu đoạn bên trái nhiều hơn 1 phần tử, cập nhật right
= i, lập lại với đoạn left, right mới tương tự. – Khi đoạn bên trái hết thì ta sẽ lấy trong stack ra – Quá trình lặp lại cho đến khi stack rỗng
Nguyen Ha Giang 2009
17
QuickSort
• Bài tập: cài đặt thuật giải Quicksort không
dùng đệ quy. – Dùng DSLK, mỗi nút chứa thông tin biên trái
và biên phải của đoạn chưa được sắp
– Áp dụng ý tưởng của slide trước để cài đặt
Nguyen Ha Giang 2009
18
Postfix
• Chuyển biểu thức trung tố sang hậu tố
Trung tố
Hậu tố
(6 / 2 + 3) * (7 - 4)
6 2 / 3 + 7 4 - *
Biểu thức hậu tố dễ tính toán hơn trong máy tính
Nguyen Ha Giang 2009
19
Postfix
• Duyệt qua từng phần tử trong infix C
– Nếu C là “(“ thì push stack. – Nếu C là “)” thì lấy tất cả phần tử trong stack cho đến khi gặp “(“. Xuất ra các phần tử này – Nếu C là toán tử: lấy trong stack ra tất cả toán tử có độ ưu tiên cao hơn C, xuất những phần tử này ra ngoài, và đưa C vào stack
– Ngược lại xuất C ra ngoài (trường hợp toán
hạng)
Nguyen Ha Giang 2009
20
Postfix
(2 * 3 + 7 / 8) * (5 – 1)
Đọc Xử lý Stack Output
( ( Đẩy vào stack
2 ( 2 Xuất
Do ‘*’ ưu tiên hơn ‘(‘ ở đỉnh stack * ( * 2 nên đưa ‘*’ vào stack
3 ( * 2 3 Xuất
Do ‘+’ ưu tiên thấp hơn ‘*’ ở đỉnh
stack nên ta lấy ‘*’ ra. + ( + 2 3 *
Tiếp tục so sánh ‘+’ với ‘(‘ thì ‘+’ ưu tiên cao hơn nên đưa vào stack
7 ( + 2 3 * 7 Xuất
/ ( + / 2 3 * 7 Do ‘/’ có độ ưu tiên cao hơn ‘+’ trên đỉnh stack nên đưa ‘/’ vào stack.
Nguyen Ha Giang 2009
21
8 ( + / 2 3 * 7 8 Xuất
Postfix
(2 * 3 + 7 / 8) * (5 – 1)
Đọc Stack Output Xử lý
) 2 3 * 7 8 / + Lấy trong stack ra cho đến khi gặp ngoặc (.
* 2 3 * 7 8 / + * Đưa vào stack
* ( 2 3 * 7 8 / + ( Đưa vào stack
* ( 2 3 * 7 8 / + 5 5 Xuất
- * ( - 2 3 * 7 8 / + 5 Độ ưu tiên của ‘-‘ cao hơn ‘(‘ trong đỉnh stack nên đưa ‘-‘ vào stack
* ( - 2 3 * 7 8 / + 5 1 1 Xuất
) * 2 3 * 7 8 / + 5 1 - Lấy trong stack ra cho đến khi gặp ngoặc đóng
trong
Nguyen Ha Giang 2009
22
2 3 * 7 8 / + 5 1 - * Lấy những phần tử còn lại stack và hiển thị
Postfix
• Tính giá trị biểu thức postfix
Postfix không cần có dấu ngoặc vẫn có thể tính đúng bằng cách đọc lần lượt biểu thức từ trái qua phải và dùng một stack để lưu trữ kết quả trung gian
34*5+
Nguyen Ha Giang 2009
23
Jan Lukasiewicz
Postfix
Ý tưởng • Khởi tạo stack = {Ø} • Đọc lần lượt các phần tử từ trái, kiểm tra
– Nếu toán hạng: Push stack – Nếu toán tử: lấy hai toán hạng, thực hiện
phép toán, kết quả Push vào stack • Sau khi đọc xong, trong stack còn duy
nhất một phần tử kết quả!
Nguyen Ha Giang 2009
24
Nguyen Ha Giang 2009
25
Giới thiệu
• FIFO • Thêm vào cuối và lấy ra ở đầu
Nguyen Ha Giang 2009
26
Mô tả
• Queue dùng DSLK
– Con trỏ pFront trỏ đầu danh sách – Con trỏ pRear trỏ đến cuối danh sách – Thao tác Remove diễn ra ở pFront – Tháo tác Insert diễn ra ở pRear – Thao tác thêm xoá dễ dàng ở hai đầu
Nguyen Ha Giang 2009
27
Mô tả
• Tạo cấu trúc Node cho Queue
typedef struct node {
info; DataType struct node * next;
}NODE; typedef NODE * NodePtr; struct Queue {
NodePtr NodePtr
pFront; pRear;
}
Nguyen Ha Giang 2009
28
Thao tác
• Các thao tác trên Queue
– Init – Insert – Remove – QueueFront – QueueRear – QueueSize – Clear
Nguyen Ha Giang 2009
29
Insert
• Insert
pFront
pRear
new
5
2
9
x
pFront
pRear
new
5
2
9
x
Nguyen Ha Giang 2009
30
Insert
void Insert(Queue &queue, int x) {
NodePtr node; node = NewNode(); node->info = x; node->next = NULL; if ( queue.pRear == NULL) { queue.pRear = node; queue.pFront = node;
} else {
queue.pRear->next = node; queue.pRear = node;
}
}
Nguyen Ha Giang 2009
31
Remove
• Remove
pFront
pRear
5
2
9
pFront
pRear
2
9
Nguyen Ha Giang 2009
32
Remove
int Remove(Queue & queue) {
NodePtr p; int value; if (queue.pFront == NULL) {
printf(“Queue is empty!”); return -1;
} if (queue.pFront == queue.pRear) { p = queue.pFront; queue.pFront = queue.pRear = NULL;
} else {
p =queue.pFront; queue.pFront = p->next;
} value = p->info; FreeNode(p); return value;
Nguyen Ha Giang 2009
33
}
ứng dụng
• Ứng dụng Queue
– Trong bài toán hàng đợi “Vào trước ra trước”
FIFO: • Hệ thống print server • Cơ chế thông điệp, bộ đệm, hàng đợi xử lý sự
kiện…
• Các ứng dụng đặt vé tàu lửa, máy bay… • Các hệ thống rút tiền…
Nguyen Ha Giang 2009
34