TS. Lê Minh Trung ThS. Lương Trần Ngọc Khiết Khoa Công nghệ Thông tin- Đại học Sư phạm TP. HCM
Ngăn Xếp (Stack)
Sử dụng mảng Sử dụng con trỏ Ứng dụng của ngăn xếp
Mô tả stack
Một stack là một cấu trúc dữ liệu mà việc thêm vào và loại bỏ được thực hiện tại một đầu (gọi là đỉnh – top của stack).
Là một cấu trúc vào sau ra In
trước – LIFO (Last First Out)
Hoạt động của Stack
Stack rỗng:
Q
Đẩy (push) Q vào:
A
Q
Đẩy A vào:
A
Lấy (pop) ra một => được A:
Q
Lấy ra một => được Q và stack rỗng:
Q
Hoạt động của Stack
Thiết kế của Stack
template
public:
};
Stack(void); //phương thức khởi tạo
Stack(const Stack
Cài đặt Stack sử dụng mảng http://www.cs.usfca.edu/~galles/visualization/StackArray.html
Thiết kế Stack dùng mảng
const int MAX=20; //stack có tối đa MAX phần tử
template
Các phương thức
template
template
top =-1;
return top==-1; //stack rỗng
}
}
template
template
top =-1;
return top== MAX-1; //stack đầy
}
}
Các phương thức
template
if(!IsFull()){
top++; data[top]= item;
}else {
throw exception("Stack is full");
}
}
Các phương thức
template
if(!IsFull()){
top++; data[top]= item;
}else {
throw exception("Stack is full");
}
}
template
if(!IsEmpty()){
top--;
}else {
throw exception("Stack is empty");
}
}
Thử nghiệm
#include "Stack.cpp"
#include
void main(){
Stack
cout << setw(4)< }
cout< } Thử nghiệm #include "Stack.cpp"
#include void main(){ Stack for(int i=1;i<=100;i++)s.Push(i);
while(!s.IsEmpty()){ cout << setw(4)< } cout< }catch(exception &e){ cout<< e.what(); cout< } } Cần: Dữ liệu
Con trỏ để trỏ đến node sau
Constructor Thiết kế Node template NodeType item; // dữ liệu của Node
Node }; #include "Node.h" template template *ptr=nullptr) { this->item= item;
this->next = ptr; } Node p1 p2 first_node p0 a b c #include "Node.h"
template }; Giải thuật 1. Tạo ra một node mới với giá trị cần thêm vào
2. Trỏ nó đến đỉnh hiện tại của stack
3. Trỏ đỉnh của stack vào node mới
new_top new_node top_node old top middle last template Node top = newTop; throw exception("Not enough memory"); }else{ } } Giải thuật: 1. Gán một con trỏ để giữ đỉnh của stack
2. Trỏ đỉnh của stack vào node ngay sau đỉnh hiện tại
3. Xóa node cũ đi top_node old top middle old last old_top template Node } Sự không an toàn con trỏ trong C++ Kết thúc biến stack nhưng bộ nhớ còn lại: delete stack0; stack0 Gán hai stack: cả hai dùng chung một vùng dữ liệu top middle last stack2 = stack1; stack2 top middle last stack1 top middle last Destructor (phương thức hủy): Sẽ được gọi ngay trước khi đối tượng kết thúc thời gian sống
Dùng xóa hết vùng dữ liệu Copy constructor: Sẽ được gọi khi khởi tạo biến lúc khai báo, hoặc truyền dữ liệu Sao chép nguồn thành một vùng dữ liệu mới Assignment operator (toán tử gán): Sẽ được gọi khi gán đối tượng này vào đối tượng khác
Xóa vùng dữ liệu của đích và đồng thời sao chép nguồn thành một bằng tham trị vùng dữ liệu mới Hủy vùng nhớ đã được cấp cho Stack
template while(!IsEmpty())Pop(); } template Clear(); } copy.top_node a b c copy_node new_copy new_top a b c Giải thuật: 1. Tạo một đỉnh của danh sách mới với dữ liệu của đỉnh nguồn
2. Giữ một con trỏ đuôi chỉ vào cuối danh sách mới
2. Duyệt qua danh sách nguồn 2.1. Tạo một node mới với dữ liệu từ node nguồn hiện tại
2.2. Nối vào cuối danh sách mới
2.3. Con trỏ đuôi là node mới template Node sCur = sCur ->next;
newCur->next = new Node }
return newTop; } Copy constructor và toán tử gán template top = Copy(source); } template &source) { } Clear(); //xóa dữ liệu cũ của stack
top = Copy(source); //trỏ tới dữ liệu mới return (top==nullptr); } template return top ->item; } #include void main(){ Stack cout<< sStr.Peek() << " ";
sStr.Pop(); }
cout<< endl;
cin.get(); } Thử nghiệm void main(){ try{
Stack s.Push(i);
cout << "Cap phat # " << i< } }catch(exception &e){ cout<< e.what()<< endl; }
cin.get(); } Sử dụng trong nhiều bài toán, thuật toán…
Khử đệ qui
Kí pháp nghịch đảo Ba Lan (Reserve Polish Notation) Cho trước biểu thức: (2+4)*5 – (3-2)*4 Biểu thức trung tố (infix) 1. Có thể biểu diễn biểu thức ở dạng khác mà không cần dấu ( ) hay không?
2 4 + 5 * 3 2 – 4 * -
o o Biểu thức tiền tố (postfix) 2. Lượng giá biểu thức như thế nào? 2 4 + 5 * 3 2 – 4 * - 6 5 * 3 2 – 4 * - 30 3 2 – 4 * - o
30 1 4 * - 30 4 - 26 Đọc lần lượt các thành phần của biểu thức từ trái sang phải, với mỗi thành phần được đọc thực hiện các bước sau: Nếu thành phần được đọc là toán hạng od thì đẩy nó vào ngăn xếp, tức là S. Push (od). Nếu thành phần được đọc là phép toán op thì lấy ra các toán hạng ở đỉnh ngăn xếp: Thực hiện phép toán op với các toán hạng là od 1 và od 2, kết Lặp lại hai bước trên cho tới khi thành phần cuối cùng của
biểu thức được đọc qua. Khi đó ngăn xếp chứa kết quả của biểu
thức. 1. Push(5); Push(8); Push(3); Push(1);
2. 4
1217
3
1
2 r = 3-1 =2; Push(r);
r = 8 / 2 =4; Push(r); 54
5
8
3 5
8
5 5 3.
4. Push(3);
5. 6. r = 4*3=12; Push(r);
r = 5 + 12 =17; Push(r); Chuyển đổi infix thành postfix Thứ tự ưu tiên của toán tử: (), * / , + - 1. Nếu thành phần được đọc là toán hạng thì viết nó vào biểu thức postfix.
2. Nếu thành phần được đọc là phép toán (phép toán hiện thời), thì thực hiện các 3. Nếu thành phần được đọc là dấu mở ngoặc thì nó được đẩy vào ngăn xếp.
4. Nếu thành phần được đọc là dấu đóng ngoặc thì thực hiện các bước sau: 1. (Bước lặp) Loại các phép toán ở đỉnh ngăn xếp và viết vào biểu thức postfix
cho tới khi đỉnh ngăn xếp là dấu mở ngoặc. 2. Loại dấu mở ngoặc khỏi ngăn xếp. 5. Sau khi toàn bộ biểu thức infix được đọc, loại các phép toán ở đỉnh ngăn xếp và viết vào biểu thức postfix cho tới khi ngăn xếp rỗng.Cài đặt Stack sử dụng con trỏ
http://www.cs.usfca.edu/~galles/visualization/StackLL.html
Thiết kế Node
Node
Thiết kế Node
Ví dụ với Node liên kết
Stack liên kết
Thiết kế Stack
Thêm vào một stack liên kết
Phương thức Push
Bỏ đỉnh của một stack liên kết
Phương thức Pop
Đảm bảo an toàn con trỏ trong C++
Sao chép vùng dữ liệu – Ví dụ
Sao chép vùng dữ liệu
Sao chép vùng dữ liệu
Phương thức khác
template
Thử nghiệm
Ứng dụng của Stack
Ước lượng biểu thức
Lượng giá biểu thức postfix
od 2 = S.PopAndPeek( )
od 1 = S.PopAndPeek( )
quả được đẩy vào ngăn xếp:
r = od 1 op od 2
S. Push(r)
Ví dụ
Input: 5 8 3 1 - / 3 * +
bước sau:
1. Nếu ngăn xếp không rỗng thì nếu phần tử ở đỉnh ngăn xếp là phép toán có
quyền ưu tiên cao hơn hay bằng phép toán hiện thời, thì phép toán đó
được kéo ra khỏi ngăn xếp và viết vào biểu thức postfix. Lặp lại bước này.
2. Nếu ngăn xếp rỗng hoặc phần tử ở đỉnh ngăn xếp là dấu mở ngoặc hoặc
phép toán ở đỉnh ngăn xếp có quyền ưu tiên thấp hơn phép toán hiện
thời, thì phép toán hiện thời được đẩy vào ngăn xếp.
Ví dụ
Input: a * ( b – c + d) + e / f
a b c – d + * e f / +
CÁM ƠN VÌ ĐÃ
LẮNG NGHE!