Stack số nguyên – Sử dụng mảngstruct ttStack { int* StkArray; // mảng chứa các phần tử int StkMax; // số phần tử tối đa int StkTop; // vị trí đỉnh Stack }; typedef struct ttStack STACK ;
Trang 1C HƯƠNG 5
K IỂU N GĂN X ẾP , H ÀNG Đ ỢI , Đ Ệ Q UY
GV Th.S Thiều Quang Trung Trường Cao đẳng Kinh tế Đối ngoại
Trang 2• Khái niệm ngăn xếp
Trang 3Ngăn xếp - Định nghĩa
• Stack là 1 cấu trúc:
– Gồm nhiều phần tử
– Hoạt động theo cơ chế “Vào sau – Ra trước”
(LIFO – Last In, First Out)
Đỉnh ngăn xếp
Trang 4Thao 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 Stack
• Pop : lấy ra 1 phần tử khỏi Stack
Trang 5Thao tác thêm - Push vào Stack
Trang 6Thao tác lấy - Pop khỏi stack
Top
Trang 7Ví dụ thêm và xóa phần tử trong stack
Nhập 7
1 5 7
Nhập 3
1 5 7 3
Trang 9Stack – Sử dụng mảng
9 3 6
Stack
Top
Trang 10Stack số nguyên – Sử dụng mảng
struct ttStack
{
int* StkArray; // mảng chứa các phần tử
int StkMax; // số phần tử tối đa
int StkTop; // vị trí đỉnh Stack };
typedef struct ttStack STACK ;
Trang 16Bài tập
• Viết hàm nhập và xuất Stack số nguyên
• Khai báo cấu trúc và viết hàm tạo Stack từ
chuỗi ký tự str (mỗi phần tử Stack là ký tự)
• Khai báo cấu trúc và viết hàm tạo Stack từ
chuỗi ký tự str (mỗi phần tử Stack là một từ
- từ cách nhau bởi khoảng trắng)
Trang 17Stack – 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ự
• Kinh tế Đối ngoại ➔ iạogn iốĐ ết hniK
Trang 18Stack – Sử dụng DSLK
9 7
Trang 28Stack – 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 29Stack – 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 30Hàng đợi Queue
Phòng vé
Trang 31Queue – Định nghĩa
• Hàng đợi là một cấu trúc:
– Gồm nhiều phần tử có thứ tự
– Hoạt động theo cơ chế “Vào trước, ra trước”
(FIFO - First In First Out)
Trang 32Queue – Đị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?
đợ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
Trang 33• Minh họa thao tác EnQueue
• Minh họa thao tác DeQueue
Trang 34Cách xây dựng Queue
– Sử dụng mảng một chiều
– Sử dụng danh sách liên kết đơn
Trang 35Queue – Sử dụng mảng
• Dùng 1 mảng ( QArray ) để chứa các phần tử.
• Dùng 1 số nguyên ( QMax )để lưu số phần tử tối
đa trong hàng đợi
• Dùng 2 số nguyên ( QFront , QRear ) để xác định
vị trí đầu, cuối hàng đợi
• Dùng 1 số nguyên ( QNumItems ) để lưu số phần
tử hiện có trong hàng đợi
Trang 38QRear = 6
Trang 411 Thêm giá trị 123 vào hàng đợi
Trang 422 Lấy một phần tử khỏi hàng đợi
Trang 433 Thêm giá trị 456 vào hàng đợi
Trang 51Queue – Ví dụ ứng dụng
• Quản lý việc thực hiện các tác vụ (task) trong môi
trường xử lý song song
• Hàng đợi in ấn các tài liệu
• Vùng nhớ đệm (buffer) dùng cho bàn phím
• Quản lý thang máy
Trang 53Queue – Sử dụng DSLK
• Các thao tác cơ bản
bool InitQueue(QUEUE &q);
bool IsEmpty( const QUEUE &q);
bool IsFull( const QUEUE &q);
bool EnQueue(QUEUE &q, int newitem);
Trang 59Khái niệm đệ qui
• Khái niệm: đệ qui là hình thức có dùng lại chính nó.
– Ví dụ: giai thừa của n là 1 nếu n là 0 hoặc là n nhân cho giai thừa của n-1 nếu n > 0
• Quá trình đệ qui gồm 2 phần:
– Trường hợp cơ sở (base case)
– Trường hợp đệ qui: cố gắng tiến về trường hợp cơ sở
• Ví dụ trên:
– Giai thừa của n là 1 nếu n là 0
– Giai thừa của n là n * (giai thừa của n-1) nếu n>0
Trang 61Thi hành hàm tính giai thừa
n=2
… 2*factorial(1)
factorial (2)
n=1
… 1*factorial(0)
Trang 62Trạng thái hệ thống khi thi hành hàm tính giai thừa
factorial(3) factorial(3)
factorial(2)
factorial(3) factorial(2) factorial(1)
factorial(3) factorial(2) factorial(1) factorial(0)
factorial(3) factorial(2) factorial(1)
Gọi hàm factorial(1)
Gọi hàm factorial(0)
Trả về từ hàm factorial(0)
Trả về từ hàm factorial(1)
Trả về từ hàm factorial(2)
Trả về từ hàm factorial(3)
Stack hệ thống
Thời gian hệ thống
t
Trang 63Bài toán Tháp Hà nội
• Luật:
– Di chuyển mỗi lần một đĩa
– Không được đặt đĩa lớn lên trên đĩa nhỏ
Trang 64Bài toán Tháp Hà nội – Thiết kế hàm
Trang 65Bài toán Tháp Hà nội – Mã C++
void move(int count, int start, int finish, int
temp) {
if (count > 0) {
move(count − 1, start, temp, finish);
cout << "Move disk " << count << "
from " << start
<< " to " << finish << "." << endl;
move(count − 1, temp, finish, start);
}
Trang 66Bài toán Tháp Hà nội – Thi hành
Trang 67Bài toán Tháp Hà nội – Cây đệ qui
Trang 68Thiết kế các giải thuật đệ qui
• Tìm bước chính yếu (bước đệ qui)
• Tìm qui tắc ngừng
• Phác thảo giải thuật
– Dùng câu lệnh if để lựa chọn trường hợp.
• Kiểm tra điều kiện ngừng
– Đảm bảo là giải thuật luôn dừng lại.
• Vẽ cây đệ qui
– Chiều cao cây ảnh hưởng lượng bộ nhớ cần thiết.
– Số nút là số lần bước chính yếu được thi hành.
Trang 69Đệ qui đuôi (tail recursion)
• Định nghĩa: câu lệnh thực thi cuối cùng là lời gọi đệ qui đến chính nó.
• Khử: chuyển thành vòng lặp.
Trang 70Khử đệ qui đuôi hàm giai thừa
• Giải thuật:
product=1
for (int count=1; count < n; count++)
product *= count;
Trang 72Dãy số Fibonacci – Cây thi hành
Đã tính rồi
Trang 73Dãy số Fibonacci – Khử đệ qui
• Nguyên tắc:
– Dùng biến lưu trữ giá trị đã tính của Fn-2
– Dùng biến lưu trữ giá trị đã tính của Fn-1
– Tính Fn = Fn-1 + Fn-2 và lưu lại để dùng cho lần sau
• Giải thuật:
int Fn2=0, Fn1=1, Fn;
for (int i = 2; i <= n; i++) {
Fn = Fn1 + Fn2;