6.2 Nganxep

You might also like

Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1of 27

BÀI 6.

CÁC THUẬT TOÁN VỚI NGĂN XẾP


2

TỔNG HỢP CÁC CẤU TRÚC DỮ LIỆU

Trang 2
3

NGĂN XẾP

Ngăn xếp là gì?


• Là một danh sách nhưng các phép toán chỉ được thực hiện ở một đỉnh
của danh sách.

Tính chất
• Vào trước ra sau (First In Last Out: FILO)

Trang 3
4

NGĂN XẾP

Trừu tượng hóa cấu trúc ngăn xếp


 Đặc tả dữ liệu
A = (a0, a1, …, an-1)
trong đó an-1 là đỉnh ngăn xếp
 Đặc tả các phép toán
1. Thêm phần tử x vào đỉnh ngăn xếp: push(x)
2. Loại phần tử ở đỉnh ngăn xếp: pop()
3. Kiểm tra ngăn xếp có rỗng hay không: isEmpty()
4. Kiểm tra ngăn xếp có đầy hay không: isFull()
5. Đếm số phần tử của ngăn xếp: size()
6. Trả về phần tử ở đỉnh ngăn xếp: top()

Trang 4
Hai phương pháp biểu diễn ngăn xếp
Biểu diễn liên tục: các phần tử dữ liệu của ngăn xếp được lưu trữ liên tục nhau
trong bộ nhớ (Mảng).
Biểu diễn rời rạc: các phần tử dữ liệu của ngăn xếp được lưu trữ rời rạc nhau
trong bộ nhớ (Danh sách liên kết).
Ví dụ. Biểu diễn ngăn xếp dựa vào mảng.
typedef struct {
int top; //Đỉnh đầu của stack nơi diễn ra mọi thao tác
int node[MAX]; //Dữ liệu lưu trữ trong stack gồm MAX phần tử
} Stack;
top node[top]

top top

node[top]

node[top] Trang 5
CÀI ĐẶT NGĂN XẾP SỬ DỤNG MẢNG

Các thao tác:


 Kiểm tra tích rỗng của stack (Empty(stack s)).
 Kiểm tra tính đầy của ngăn xếp (Full(stack s)).
 Đưa dữ liệu vào ngăn xếp (Push(stack s, item x)). Chỉ được thực
hiện khi và chỉ khi ngăn xếp chưa tràn.
 Đưa dữ liệu vào ngăn xếp (Pop(stack s). Chỉ được thực hiện khi
và chỉ khi ngăn xếp không rỗng.

Ví dụ. Trạng thái rỗng, trạng thái đầy của stack.


Top= MAX-1
MAX-1 MAX-1 9
… … 7
2 2 5
1 1 3
0 0 1 Trang 6
CÀI ĐẶT NGĂN XẾP SỬ DỤNG MẢNG

Trang 7
CÀI ĐẶT NGĂN XẾP SỬ DỤNG MẢNG

Kiểm tra tính đầy của stack:

int Full( stack *s ) {


if ( stack ->top == MAX-1 )
return (1);
return(0);
}

Trang 8
CÀI ĐẶT NGĂN XẾP SỬ DỤNG MẢNG

Trang 9
CÀI ĐẶT NGĂN XẾP SỬ DỤNG MẢNG

Trang 10
Ví dụ. Cho stack lưu trữ tối đa 5 phần tử. Bắt đầu thực hiện tại trạng thái
rỗng.
top =-1 top =0 top =1 top =2 top =3 top =4
Push(s,9) 9
Push(s,7)
7 7
Push(s,5)
5 5 5
Push(s,3)
3 3 3 3
Push(s,1)
1 1 1 1 1

top =4 top =3 top =2 top =1 top =0 top =-1

9 Pop(s)
Pop(s)
7 7
Pop(s)
5 5 5
Pop(s)
3 3 3 3
Pop(s)
1 1 1 1 1
Trang 11
Các thao tác trên stack dựa danh sách liên kết đơn
Stack = { DSLK đơn + [<Add-Top:(Push)>; <Del-Top: (Pop)> ] }
Stack = { DSLK đơn + [<Add-Bottom:(Push)>; <Del-Bottom: (Pop)> ] }

Các thao tác trên stack:


struct node{
int info;
struct node *link;
}*Stack;
class stack_list{
public:
node *push(node *, int);
node *pop(node *);
void traverse(node *);
stack_list(){ Stack = NULL; }
}; Trang 12
node *stack_list::push(node *Stack, int item){
node *tmp; tmp = new (struct node);
tmp->info = item; tmp->link = Stack; Stack = tmp;
return Stack;
}
node *stack_list::pop(node *Stack){ node *tmp;
if (Stack == NULL) cout<<"Stack rỗng"<<endl;
else { tmp = Stack;
cout<<“Node đã bị loại bỏ: "<<tmp->info<<endl;
Stack = Stack->link; free(tmp);
}
return Stack;
}
void stack_list::traverse(node *Stack){
node *ptr; ptr = Stack;
if (Stack == NULL) cout<<"Stack rỗng"<<endl;
else { cout<<“Các phần tử của stack :"<<endl;
while (ptr != NULL) {
cout<<ptr->info<<endl; ptr = ptr->link;
}
} Trang 13
}
ỨNG DỤNG CỦA NGĂN XẾP

 Khử đệ quy

 Kiểm soát dấu ngoặc

 Biểu diễn và chuyển đổi giữa các cách biểu diễn phép toán

 Duyệt cây, duyệt đồ thị…

Trang 14
THƯ VIỆN STL TRONG C++

<array> <set>
<vector> <multiset>
<deque> <map>
<forward_list> <multimap>
<list> <unordered_set>
<stack> <unordered_multiset>
<queue> <unordered_map>
<priority_queue> <unordered_multimap>
<bitset>
<valarray>
Trang 15
1
6
Ví dụ khai báo và sử dụng stack

#include <iostream>
#include <stack>
#include <conio.h>
using namespace std;
int main ()
{
stack<int> mystack;
for (int i=0; i<5; ++i) mystack.push(i*2);
cout << "Thuc hien phep pop cac phan tu ...";
while(!mystack.empty()){
cout << ' ' << mystack.top();
mystack.pop();
}
cout << '\n';
return 0;
}

Trang 16
1
7
Minh họa các thao tác

thao tác output ngăn xếp


push(3) (3)
push(5) (3, 5)
pop() (3)
top() 3 (3)
push(8) (3, 8)
pop() (3)
size() 1 (3)
pop() ()
pop() lỗi: ngăn xếp rỗng ()
push(15) (15)
top() 15 (15)

Trang 17
1
8
NHẬN XÉT VỀ NGĂN XẾP

Ưu điểm
• Gọi n là số phần tử của ngăn xếp

• Không gian sử dụng là O(n)

• Mỗi thao tác thực hiện trong thời gian O(1)

Hạn chế (với cách cài đặt bằng mảng)


• Kích thước tối đa của ngăn xếp phải được chỉ định trước và không thể thay đổi

• Cố push phần tử mới vào ngăn xếp đã đầy sẽ sinh ngoại lệ do cài đặt
(implementation-specific exception)

Trang 18
1
9
Ví dụ: Kiểm tra biểu thức dấu ngoặc cân xứng

Mỗi ngoặc mở “(“, “[“, “{“ phải được cặp với một ngoặc
đóng “)“, “]“, “}“ tương ứng.

Ví dụ
• cân xứng: ( )(( )){([( )])}
• không cân xứng: ((( )(( )){([( )])}
• không cân xứng: )(( )){([( )])}
• không cân xứng: ({[ ])}
• không cân xứng: (

Trang 19
CHUYỂN ĐỔI TRUNG TỐ - HẬU TỐ

Biểu thức Hậu tố:


•a+bab+
•a-bab-
•a*bab*
•a/bab/
• (P)  P

a  b * c   a / b  c  
 a  bc *  ab /  c 
 abc *    ab / c  
 abc *   ab / c 
 abc *  ab / c  
Trang 20
Thuật toán chuyển đổi biểu thức trung tố P thành biểu thức hậu tố

Bước 1 (Khởi tạo): stack = ; Out = ;


Bước 2 (Lặp) :
For each xP do
2.1. Nếu x =‘ (‘ : Push(stack, x);
2.2. Nếu x là toán hạng: xOut;
2.3. Nếu x  { +, -, *, / }
y = get(stack);
a) Nếu priority(x)priority(y): Push(stack, x);
b) Nếu priority(x)<priority(y):
y = Pop(stack); yOut; Push(stack, x);
c) Nếu stack = : Push(stack, x);
2.4. Nếu x =‘)’:
y = Pop(stack);
While (y!=‘(’ ) do
yOut; y = Pop(stack);
EndWhile;
EndFor;
Bước 3(Hoàn chỉnh biểu thức hậu tố):
While (stack  ) do
y = Pop(stack); yOut;
EndWhile;
Bước 4(Trả lại kết quả):
Return(Out).
Trang 21
Kiểm nghiệm thuật toán: P = a  b * c   a / b  c 
xP Bước Stack Out
x =‘(‘ 2.1 ( 
x =a 2.2 ( a
x =+ 2.3.a (+ a
x =b 2.2 (+ ab
x =* 2.3.a (+* ab
x=c 2.2 (+* abc
x =‘)‘ 2.3  abc*+
x =- 2.2.c - abc*+
x =‘(‘ 2.1 -( abc*+
x =a 2.2 -( abc*+a
x =/ 2.2.a -(/ abc*+a
x =b 2.2 -(/ abc*+ab
x =+ 2.3.b -(+ a b c * + a b/
x =c 2.2 -(+ a b c * + a b/c
x =‘)‘ 2.4  a b c * + a b/c + -
P = a b c * + a b/c + - Trang 22
TÍNH TOÁN BIỂU THỨC HẬU TỐ

Thuật toán tính toán giá trị biểu thức hậu tố?
Bước 1 (Khởi tạo):
stack = ;
Bước 2 (Lặp) :
For each xP do
2.1. Nếu x là toán hạng:
Push( stack, x);
2.2. Nếu x  { +, -, *, / }
a) TH2 = Pop(stack, x);
b) TH1 = Pop(stack, x);
c) KQ = TH1  TH2;
d) Push (stack, KQ);
EndFor;
Bước 4(Trả lại kết quả):
Return(Pop(stack)).

Trang 23
Ví dụ: P = 6 2 4 * + 6 2 / 4 + -

4 2 4
2 8 6 3 3 7
* + / / + -
6 6 14 14 14 14 7

Trang 24
BÀI TOÁN: PHẦN TỬ BÊN PHẢI ĐẦU TIÊN LỚN HƠN

MÔ TẢ BÀI TOÁN
Cho dãy số A[] gồm N phần tử. Với mỗi A[i], bạn cần tìm phần tử bên phải
đầu tiên lớn hơn nó. Nếu không tồn tại, in ra -1.

VÍ DỤ:
Dãy A[] = {4, 5, 2, 25}

KẾT QUẢ: R[] = {5, 25, 25, -1}

GIẢI THUẬT:
•Cách làm thông thường: độ phức tạp O(n2)
•Sử dụng Stack: độ phức tạp O(n)

Trang 25
BÀI TOÁN: PHẦN TỬ BÊN PHẢI ĐẦU TIÊN LỚN HƠN

CÀI ĐẶT
void xuly(int a[], int n){
stack<int> st;
int R[n], i;
for(i=n-1;i>=0;i--){
while(!st.empty() && a[i] >= st.top()) st.pop();
if(st.empty()) R[i] = -1;
else R[i] = st.top();
st.push(a[i]);
}
for(i=0;i<n;i++) cout << R[i] << " ";
cout << endl;
}

Trang 26
MỘT SỐ BÀI TOÁN ÁP DỤNG KHÁC

1. Chuyển đổi giữa các dạng biểu thức:


• Trung tố
• Hậu tố
• Tiền tố
2. Kiểm tra dư thừa dấu ngoặc
3. Tính độ dài dãy ngoặc đúng dài nhất
4. Đếm số dấu ngoặc cần đổi chiều
5. Tính diện tích hình chữ nhật lớn nhất

Trang 27

You might also like