Ngăn xếp - Định nghĩa• Các thao tác cơ bản trên Stack: • InitStack: khởi tạo Stack rỗng • IsEmpty: kiểm tra Stack rỗng?. • Push: thêm 1 phần tử vào đỉnh Stack, có thể làm Stack đầy • Pop
Trang 1STACK & QUEUE
NGĂN XẾP & HÀNG ĐỢI
Trang 3Ngăn xếp (Stack)
Chồng khay
Các ví dụ về Ngăn xếp
Trang 5Ngăn xếp - Định nghĩa
• Các thao tác cơ bản trên Stack:
• InitStack: khởi tạo Stack rỗng
• IsEmpty: kiểm tra Stack rỗng ?
• IsFull: kiểm tra Stack đầy ?
• Push: thêm 1 phần tử vào đỉnh Stack, có thể làm Stack đầy
• Pop: lấy ra 1 phần tử từ đỉnh Stack, có thể làm Stack rỗng
• StackTop: kiểm tra phần tử đầu Stack
Trang 6Ngăn xếp
• Minh họa thao tác Push
Data
Top
Trang 7Ngăn xếp
• Minh họa thao tác Pop
Data Top
Trang 8Ngăn xếp
• Minh họa thao tác StackTop
Ngăn xếp không thay đổi
Data
Top
?
?
Trang 9Ngăn xếp
• Có hai cách để xây dựng ngăn xếp
• Sử dụng mảng 1 chiều
• Sử dụng danh sách liên kết đơn
Trang 10Ngăn xếp – Sử dụng mảng
9 3 6
Stack
Top
Trang 11int StkMax; // số phần tử tối đa
int StkTop; // vị trí đỉnh Stack
};
Trang 12Ngăn xếp – Sử dụng mảng
• Thao tác “Khởi tạo Stack rỗng”
int InitStack(STACK& s, int MaxItems)
s.StkTop = -1; // chưa có phần tử nào trong Stack
return 1; // khởi tạo thành công
}
Trang 13Ngăn xếp – Sử dụng mảng
• Thao tác “Kiểm tra Stack rỗng”
int IsEmpty(const STACK &s)
Trang 14Ngăn xếp – Sử dụng mảng
• Thao tác “Kiểm tra Stack đầy”
int IsFull(const STACK &s)
{
if (s.StkTop==s.StkMax-1)
return 1; // Stack đầy
return 0; // Stack chưa đầy
}
Trang 16Ngăn xếp – Sử dụng mảng
• Thao tác “Pop”: lấy ra 1 phần tử từ đỉnh Stack
int Pop(STACK& s, int& outitem)
Trang 18Ngăn xếp – Ví dụ ứng dụng
• Kiểm tra sự tương ứng của các cặp ngoặc đơn trong một biểu thức
• ( ( A + B ) / C ( A + B ) / C)
• Đảo ngược một chuỗi ký tự
Trang 19Ngăn xếp – Sử dụng DSLK
9 7
4
NStkCnt StkTop
7Data Link
9Data Link
4Data Link
Trang 20Ngăn xếp – Sử dụng DSLK
• Cấu tạo đầu stack
• Cấu tạo một phần tử trong stack
Trang 227Data Link4
Data Link
Trang 24Ngăn xếp – Sử dụng DSLK
• Thao tác “Kiểm tra stack rỗng”:
int IsEmpty(const STACK& s)
Trang 25Ngăn xếp – Sử dụng DSLK
• Thao tác “Kiểm tra stack đầy”:
int IsFull ( const STACK s)
{
// thử tạo mới một phần tử
STACK_NODE* temp = new STACK_NODE;
// nếu không tạo được stack đầy
Trang 26return 0; // Stack đầy, không thêm vào được
STACK_NODE *pNew = new STACK_NODE;
7Data Link4
Data Link
Trang 277Data Link
4Data Link
temp
outitem = 4
Trang 29Ngăn xếp – Ứng dụng
• Stack có nhiều ứng dụng:
• Lưu vết trong thuật toán “back-tracking” (theo dõi dấu vết)
• Tính giá trị biểu thức toán học (thuật toán Balan ngược)
• Khử đệ quy
• …
Trang 30Ngăn xếp – Quick Sort
• Để khử đệ quy cho Quick Sort, ta sử dụng một stack để lưu lại các partition (phân hoạch) cần tiến hành sắp xếp
• Ý tưởng:
• Push phân hoạch đầu tiên (0, n-1) vào stack
• Trong khi stack chưa rỗng
• Pop một phân hoạch từ stack
• Chọn phần tử trục trên phân hoạch này
• Điều chỉnh phân hoạch tương ứng với trục
• Push 2 phân hoạch bên trái và phải trục vào stack
Trang 31Ngăn xếp – Quick Sort
• Push phân hoạch đầu tiên (0, n-1) vào stack
• Trong khi stack chưa rỗng
• Pop một phân hoạch từ stack
• Chọn phần tử trục trên phân hoạch này
• Điều chỉnh phân hoạch tương ứng với trục
• Push 2 phân hoạch bên trái và phải trục vào stack
Trang 32Hàng đợi (Queue)
Phòng vé
Trang 34Hàng đợi – Định nghĩa
• Các thao tác cơ bản trên hàng đợi:
• InitQueue: khởi tạo hàng đợi rỗng
• IsEmpty: kiểm tra hàng đợi rỗng ?
• IsFull: kiểm tra hàng đợi đầy ?
• EnQueue: thêm 1 phần tử vào cuối hàng đợi, có thể làm hàng đợi đầy
• DeQueue: lấy ra 1 phần tử từ đầu Queue, có thể làm Queue rỗng
• QueueFront, QueueRear: kiểm tra phần tử đầu và phần tử cuối Queue
Trang 35Hàng đợi
• Minh họa thao tác EnQueue
• Minh họa thao tác DeQueue
Trang 36Hàng đợi
• Có hai cách để xây dựng hàng đợi
• Sử dụng mảng 1 chiều
• Sử dụng danh sách liên kết đơn
Trang 37Hàng đợi – Sử dụng mảng
phần tử.
phần tử tối đa trong hàng đợi
xác định vị trí đầu, cuối hàng đợi
lưu số phần tử hiện có trong hàng đợi
Trang 38Hàng đợi – Sử dụng mảng
QMax = 7 QNumItems = 4 QFront = 1
QRear = 4
Trang 39Hàng đợi – Sử dụng mảng
// Giả sử Queue chứa các phần tử kiểu nguyên (int)
// Khai báo cấu trúc Queue
typedef struct QUEUE {
Trang 40Hàng đợi – Sử dụng mảng
• Khi thêm nhiều phần tử sẽ xảy ra hiện tượng “tràn giả”
• Giải pháp? Nối dài mảng (mảng động) hay sử dụng một mảng vô cùng lớn?
QMax = 7 QNumItems = 4 QFront = 1
QRear = 4
Trang 41QRear = 4
Trang 42Hàng đợi – Sử dụng mảng
• Thao tác “Khởi tạo Queue rỗng”:
int InitQueue(QUEUE& q, int MaxItem) {
q.QArray = new int [MaxItem];
Trang 45Hàng đợi – Sử dụng mảng
• Thao tác EnQueue: thêm 1 phần tử vào cuối Queue
int EnQueue(QUEUE &q, int newitem)
Trang 46Hàng đợi – Sử dụng mảng
• Thao tác DeQueue: lấy ra 1 phần tử ở đầu Queue
int DeQueue(QUEUE &q, int& itemout)
{
if (IsEmpty(q))
return 0; // Queue rỗng, không lấy ra được
itemout = q.QArray[q.QFront]; // lấy phần tử đầu ra
q.QFront++;
q.QNumItems ;
if (q.QFront==q.QMax) // nếu đi hết mảng …
q.QFront = 0; // … quay trở về đầu mảng
if (q.QNumItems==0) // nếu lấy ra phần tử cuối cùng
q.QFront = q.QRear = -1; // khởi tạo lại Queue
return 1; // Lấy ra thành công
}
Trang 49• Quản lý thang máy
Trang 50Hàng đợi
• Bài tập lý thuyết: Hãy xây dựng 1 Queue bằng cách sử dụng danh sách liên kết đơn
• Ðịnh nghĩa cấu trúc dữ liệu
• Xây dựng các thao tác cơ bản
Trang 51Hàng đợi – Sử dụng DSLK
• Khai báo cấu trúc
typedef struct tagNODE
Trang 52Hàng đợi – Sử dụng DSLK
• Các thao tác cơ bản
int InitQueue(QUEUE& q);
int IsEmpty(const QUEUE& q);
int IsFull(const QUEUE& q);
int EnQueue(QUEUE &q, int newitem);
int DeQueue(QUEUE &q, int& itemout);
int QueueFront(const QUEUE &q, int& itemout);
int QueueRear(const QUEUE &q, int& itemout);
Trang 54Hàng đợi – Sử dụng DSLK
• Kiểm tra Queue rỗng
int IsEmpty(const QUEUE& q)
{
return (q.NumItems==0);
}
• Kiểm tra Queue đầy
int IsFull(const QUEUE& q) {
PNODE tmp = new NODE;
Trang 55Hàng đợi – Sử dụng DSLK
Trang 56Hàng đợi – Sử dụng DSLK
• Lấy ra 1 phần tử ở đầu Queue
int DeQueue(QUEUE &q, int& itemout)
Trang 57Hàng đợi – Sử dụng DSLK
• Kiểm tra 1 phần tử ở đầu Queue
int QueueFront(const QUEUE &q, int& itemout)
Trang 58Hàng đợi – Sử dụng DSLK
• Kiểm tra 1 phần tử ở cuối Queue
int QueueRear(const QUEUE &q, int& itemout)