Download as pdf or txt
Download as pdf or txt
You are on page 1of 56

CHƯƠNG 2:

KIỂU DỮ LIỆU CẤU TRÚC

TS. LÊ THỊ MỸ HẠNH


Bộ môn Công nghệ Phần mềm
Khoa Công Nghệ Thông Tin
Đại học Bách khoa – Đại học Đà Nẵng
Nội dung
n Định nghĩa cấu trúc
n Các thao tác trên cấu trúc
n Mảng cấu trúc, con trỏ cấu trúc
n Danh sách liên kết
n Ngăn xếp, Hàng đợi

12/09/2021
Cấu trúc và Hợp
n Cấu trúc (Struct)
¨ Struct là một tập hợp các phần tử dữ liệu cùng kiểu hoặc khác kiểu được gộp
chung thành một nhóm. Các phần tử này được gọi là thành viên của struct.
¨ Cú pháp
struct structure_name { Ví dụ:
<Kiểu dữ liệu thành viên số 1> <Tên thành viên số 1>; struct Student {
<Kiểu dữ liệu thành viên số 2> <Tên thành viên số 2>; char name[20];

int id;
};
¨ Định nghĩa thể hiện của struct int age;
structure_name variable_name; };
¨ Cách truy cập biến struct Student s;
?

n Biến của struct có thể được truy cập bằng cách sử dụng thể hiện
của struct theo sau bởi toán tử (.) Và sau đó là trường của struct.
n Ví dụ: s.name
s.id
s.age

12/09/2021
Cấu trúc và Hợp (2)
n Ví dụ struct trong C++
¨ Ví dụ về struct hình chữ nhật có hai chiều
rộng và chiều cao:
1 #include <iostream>
2 using namespace std;
3 struct Rectangle {
4 int width, height;
5 };
6 int main(void) {
7 struct Rectangle rec;
8 rec.width = 8;
9 rec.height = 5;
10 cout << "Dien tich hinh chu nhat la: "
11 << (rec.width * rec.height) << endl;
12 return 0;
13 }

12/09/2021
Cấu trúc và Hợp (2)
n Ví dụ struct trong C++
¨ Sử dụng phương thức và Constructor: khởi tạo dữ
liệu và phương thức để tính diện tích hình chữ nhật.
1 #include <iostream>
2 using namespace std;
3 struct Rectangle {
4 int width, height;
5 Rectangle(int w, int h) {
6 width = w;
7 height = h;
8 }
9 void areaOfRectangle() {
10 cout << "Dien tich hinh chu nhat la: " << (width * height);
11 }
12 };
13 int main(void) {
14 struct Rectangle rec = Rectangle(4, 10);
15 rec.areaOfRectangle();
16 return 0;
17 }
12/09/2021
Cấu trúc và Hợp (2)
n Hợp (Union)
¨ union là một tập hợp các phần tử dữ liệu cùng kiểu hoặc khác kiểu
được gộp chung thành một nhóm. Các phần tử này được gọi là
thành viên của union
Ví dụ:
¨ Cú pháp: // Khai báo 1 union
union Union_Name { union Hardware {
<Kiểu dữ liệu thành viên số 1> <Tên thành viên số 1>; float _cpu;
<Kiểu dữ liệu thành viên số 2> <Tên thành viên số 2>; short _ram;

int _ssd;
};
};
// Sử dụng union
int main() {
Khi được định nghĩa như ví dụ bên, union Hardware có kích thước Hardware h;
của thuộc tính có kích thước lớn nhất, trong trường hợp này h._cpu = 3.2f;
float hoặc int là 4 bytes nên union này có kích thước là 4 bytes. h._ram = 256;
Với cách sử dụng (dùng chung vùng nhớ) như trên, 3 thuộc h._ssd = 1024;
tính _cpu, _ram, _ssd ghi đè lên nhau trong quá trình sử dụng. return 0;
}
12/09/2021
Cấu trúc và Hợp (3)
n Trường hợp sử dụng // Khai báo 1 union
union union Hardware {
short _ram;
¨ Cần tiết kiệm vùng nhớ
int _ssd;
Tiết kiệm vùng nhớ sẽ
};
hữu ích với các ứng dụng
có bộ nhớ nhỏ như trong void func() {
lập trình nhúng, dung Hardware hw;
lượng bộ nhớ chỉ khoảng // (1) Đoạn code cần dùng ram
2KB (2048 bytes). hw.ram = 2048; // MB
printf("RAM: %d", hw.ram);
// (2) Đoạn code không cần dùng ram,
// nhưng cần dùng hdd
hw.ssd = 1024; // GB
printf("SSD: %d", hw.ssd);
}

12/09/2021
Cấu trúc và Hợp (4)
n Union không tên:
¨ C++ cho phép khai báo các union không tên:
union {
<Kiểu dữ liệu thành viên số 1> <Tên thành viên số 1>;
<Kiểu dữ liệu thành viên số 2> <Tên thành viên số 2>;

};
→ Khi đó các thành phần (khai báo trong union) sẽ dùng chung một vùng
nhớ → tiết kiệm bộ nhớ và cho phép dễ dàng tách các byte của một vùng
nhớ.
¨ Ví dụ: nếu các biến nguyên i , biến ký tự ch và biến thực x không đồng
thời sử dụng thì có thể khai báo chúng trong một union không tên như
sau:
Cấu trúc và Hợp (5)
n Mảng cấu trúc
¨ Một sinh viên có các thông tin bao gồm: Tên
sinh viên, mã số sinh viên, năm sinh, điểm
trung bình và số ngày nghỉ. Nhà trường cần
nhập thông tin của tất cả các sinh viên đang
theo học tại trường và lập ra danh sách các
học sinh có thành tích tốt trong học tập ( điểm
trung bình lớn hơn 7.0) để khen thưởng và
danh sách các học sinh có số ngày nghỉ lớn
hơn 3 để ra nhắc nhở sinh viên đó.

12/09/2021
Cấu trúc và Hợp (5)
n Mảng cấu trúc
void NhapMang(SinhVien a[], int &n) {
struct SinhVien { do{
char ten[20]; printf("Cho biet so Sinh vien: ");
char ma[10]; scanf("%d", &n);
int namsinh; } while (n <= 0);
float dtb; for (int i = 1; i <= n; i++) {
int songaynghi; printf("Thong tin Sinh vien thu %d la: \n", i);
}; printf("Ten: \n"); fflush(stdin); gets(a[i].ten);
void XuatMang(SinhVien a[], int n) { printf("Ma so: \n"); fflush(stdin); gets(a[i].ma);
printf("Ten\t\t Ma\t\t NamSinh\t DTB\t \tSoNgayNghi"); printf("Nam sinh :\n");
for (int i = 1; i <= n; i++) { scanf("%d", &a[i].namsinh);
printf("\n%s %s \t %d \t\t %f \t%d\n", printf("Diem Trung Binh: \n");
a[i].ten,a[i].ma,a[i].namsinh, scanf("%f", &a[i].dtb);
a[i].dtb, a[i].songaynghi); printf("So ngay nghi: \n");
} scanf("%d", &a[i].songaynghi);
} }
}
void main() {
SinhVien A[100];
int N;
NhapMang(A, N);
XuatMang(A, N);
getch();
12/09/2021
}
Cấu trúc và Hợp (4)
n Con trỏ cấu trúc #include <iostream>
using namespace std;
¨ Một biến con trỏ có thể
struct Distance {
được tạo ra không chỉ các int feet;
kiểu cơ sở như float inch;
(int, float, doube…) mà };
chúng còn có thể được tạo int main() {
cho các kiểu người dùng tự Distance *ptr, d;
định nghĩa như cấu trúc. ptr = &d;
cout << "Enter feet: "; cin >> (*ptr).feet;
¨ Truy xuất 01 trường của
cout << "Enter inch: "; cin >> (*ptr).inch;
con trỏ struct: có 02 cách cout << "Displaying information." << endl;
cout << "Distance = " << (*ptr).feet
ptr->feet tương đương với (*ptr).feet << " feet " << (*ptr).inch << " inches";
ptr->inch tương đương với (*ptr).inch return 0;
}

12/09/2021
Danh sách
n Danh sách là cấu trúc dữ liệu tuyến tính, trong đó các
phần tử dữ liệu được sắp xếp theo một thứ tự xác định
n Danh sách thuần nhất: các phần tử cùng một kiểu
n Ví dụ
¨ Danh sách sinh viên
¨ Danh sách điện thoại
¨ Danh sách môn học
¨ Danh sách bài hát
¨ Danh sách công việc

12
Trừu tượng hóa danh sách
n Đặc tả dữ liệu
— Là một dãy hữu hạn các phần tử
L = (a0, a1, … , an-1)
n Đặc tả các phép toán
— Kiểm tra danh sách có rỗng hay không
— Đếm số phần tử của danh sách
— Trả về phần tử ở vị trí thứ i của danh sách
— Thêm phần tử x vào vị trí i trong danh sách
— Thêm phần tử x vào đuôi danh sách
— Loại phần tử ở vị trí thứ i trong danh sách
13
Trừu tượng hóa danh sách
n Đặc tả dữ liệu
L = (a0, a1, …, an-1)
trong đó ai là phần tử thứ i+1 của danh sách L
Ví dụ:
L = (1, 2, 3, 3, 4, 5)
L = (‘Hùng’, ‘Cường’, ‘Sang’)
n Đặc tả các phép toán
¨ Kiểm tra danh sách có rỗng hay không: empty(L)
¨ Đếm số phần tử của danh sách: length(L)
¨ Trả về phần tử ở vị trí thứ i của danh sách: element(L, i)
¨ Thêm phần tử x vào vị trí i trong danh sách: insert(L, i, x)
¨ Thêm phần tử x vào đuôi danh sách: append(L, x)
¨ Loại phần tử ở vị trí thứ i trong danh sách: erase(L, i)

14
Ví dụ
n L = (1, 2, 3, 3, 4, 5)
n empty(L) → false
n length(L) → 6
n element(L, 0) → 1
n element(L, 2) → 3
n insert(L, 2, 10) → L = (1, 2, 10, 3, 3, 4, 5)
n append(L, -5) → L = (1, 2, 10, 3, 3, 4, 5, -5)
n erase(L, 3) → L = (1, 2, 10, 3, 4, 5, -5)
n erase(L, 1) → L = (1, 10, 3, 4, 5, -5)
15
Cài đặt danh sách bằng mảng
n Mảng một chiều tĩnh
int dayso[100];
Phanso dayphanso[15];
n Mảng một chiều động
¨ Cấp phát bộ nhớ bằng phép new
int *daysod = new int[100];
Phanso *dayphansod = new Phanso[15];
¨ Khi không dùng nữa, phải giải phóng bộ nhớ bằng phép delete
delete [] daysod;
delete [] dayphansod;
n L = (a0, a1, …, an-1)
a0 a1 … an-1 ? … ?
0 1 n-1 n MAX-1
16
Cài đặt danh sách bằng mảng
n Mảng (array)
¨ Tập hợp các phần tử (các biến) có cùng một kiểu
¨ Một phần tử cụ thể trong mảng sẽ được xác
định và truy cập bởi một chỉ số
¨ Trong C/C++, các phần tử của mảng được đặt
cạnh nhau tạo thành một khối liên tục. Địa chỉ
thấp nhất tương ứng với phần tử đầu tiên, địa
chỉ cao nhất tương ứng với phần tử cuối cùng
¨ Mảng thì có thể là một chiều hoặc nhiều chiều

17
Cài đặt danh sách bằng mảng
n insert(L, i, x)
a0 … ai-1 ai … an-1 ? ? … ?
0 … i-1 i … n-1 n n+1 MAX-1

a0 … ai-1 x ai … an-1 ? … ?
0 … i-1 i i+1 … n n+1 MAX-1

n Dồn tất cả các phần tử từ vị trí i tới vị trí n-1 về sau một vị trí
n Sau đó đặt giá trị x vào vị trí i
n Tăng số phần tử của danh sách lên 1
18
Cài đặt danh sách bằng mảng
n erase(L, i)
a0 … ai-1 ai ai+1 … an-1 ? … ?
0 … i-1 i i+1 … n-1 n MAX-1

a0 … ai-1 ai+1 … an-1 ? ? … ?


0 … i-1 i … n-2 n-1 n MAX-1

n Dồn tất cả các phần tử từ vị trí i+1 tới vị trí n-1 lên trước một vị trí
n Giảm số phần tử của danh sách đi 1
19
Danh sách
Thành phần đồng
Mảng (Array)
nhất
Truy cập ngẫu
nhiên/trực tiếp
Thành phần không
Bản ghi (Record)
đồng nhất
Cấu trúc dữ liệu

Tuyến tính Danh sách liên kết


Tổng quát
(List)

Truy cập tuần tự Vào-trước-ra-trước Hàng đợi (Queue)

Không tuyến tính Tập hợp (Set) Vào-sau-ra-trước Ngăn xếp (Stack)

20
Danh sách
n Cấu trúc dữ liệu tĩnh
¨ Một số đối tượng dữ liệu trong chu kỳ sống của nó có thể thay
đổi về cấu trúc, kích thước, như danh sách sinh viên trong lớp
có thể tăng hoặc giảm số lượng
n Nếu dùng cấu trúc dữ liệu tĩnh như mảng để biểu diễn -> thao tác
phức tạp, kém tự nhiên -> chương trình khó đọc, khó bảo trì, sử
dụng bộ nhớ kém hiệu quả -> dữ liệu chiếm vùng nhớ đã được cấp
phát trong suốt thời gian chương trình hoạt động
¨ Ví dụ: Mảng 1 chiều
n Kích thước cố định
n Chèn 1 phần tử hoặc xoá 1 phần tử rất khó
n Các phần tử được lưu trữ tuần tự với chỉ số 0, 1, .. N-1
n Truy cập phần tử ngẫu nhiên

12/09/2021
Danh sách
n Cấu trúc dữ liệu động
¨ Cấp phát động lúc chạy chương trình
¨ Các phần tử được cấp phát vùng nhớ rải rác trong bộ nhớ
¨ Kích thước danh sách chỉ bị giới hạn bởi RAM
¨ Thao tác thêm/xoá đơn giản

12/09/2021
Danh sách liên kết
n Danh sách liên kết là gì?
¨ Danh sách liên kết đơn là một tập hợp các Node được phân bố
động, được sắp xếp theo cách sao cho mỗi Node chứa “một giá
trị”(Data) và “một con trỏ”(Next). Con trỏ sẽ trỏ đến phần tử kế tiếp
của danh sách liên kết đó. Nếu con trỏ mà trỏ tới NULL, nghĩa là
đó là phần tử cuối cùng của linked list.
¨ hình ảnh mô phỏng một danh sách liên đơn kết đầy đủ

¨ một Node trong danh sách liên kết đơn: Data Next
10 pointer

12/09/2021
Danh sách liên kết (2)
n Các kiểu danh sách liên kết:
¨ Danh sách liên kết đơn(Single linked list): Chỉ có sự
kết nối từ phần tử phía trước tới phần tử phía sau.
A B C D

¨ Danh sách liên kết đôi(Double linked list): Có sự kết


nối 2 chiều giữa phần tử phía trước với phần tử phía
sau
A B C D

12/09/2021
Danh sách liên kết (2)
n Các kiểu danh sách liên kết:
¨ Danh sách liên vòng: Phần tử cuối danh sách liên với
phần tử đầu danh sách
¨ Danh sách liên kết đơn vòng

A B C D
¨ Danh sách liên kết đôi vòng

A B C D

12/09/2021
Danh sách liên kết (3)
n Cài đặt danh sách liên kết đơn (linked list)
¨ Khai báo LinkedList struct LinkedList{
int data;
n data lưu giữa giá trị
struct LinkedList *next;
n next là con trỏ đến node kế tiếp };
¨ Tại sao next lại là kiểu LinkedList của chính nó?
¨ Tạo mới 1 Node

typedef struct LinkedList *node;


//Từ giờ dùng kiểu dữ liệu LinkedList có thể thay bằng node cho ngắn gọn

node CreateNode(int value){


node temp; // declare a node
temp = new node; // Cấp phát vùng nhớ
temp->next = NULL;// Cho next trỏ tới NULL
temp->data = value; // Gán giá trị cho Node
return temp;//Trả về node mới đã có giá trị
}
12/09/2021
Danh sách liên kết (4)
n Thêm Node vào danh sách liên kết
¨ Thêm vào đầu

1 node AddHead(node head, int value){


2 node temp = CreateNode(value); // Khởi tạo node temp với data = value
3 if (head == NULL){
4 head = temp; // //Nếu linked list đang trống thì Node temp là head
5 luôn
6 }else{
7 temp->next = head; // Trỏ next của temp = head hiện tại
8 head = temp; // Đổi head hiện tại = temp(Vì temp bây giờ là head mới
9 mà)
10 }
return head;
}

12/09/2021
Danh sách liên kết (4)
n Thêm Node vào danh sách liên kết
¨ Thêm vào cuối
1 node AddTail(node head, int value){
2 node temp,p;// Khai báo 2 node tạm temp và p
3 //Gọi createNode để khởi tạo node temp có next trỏ tới NULL và giá trị là value
4 temp = CreateNode(value);
5 if(head == NULL){
6 head = temp; //Nếu linked list đang trống thì Node temp là head luôn
7 }
8 else{
9 p = head;// Khởi tạo p trỏ tới head
10 while(p->next != NULL){
11 p = p->next;//Duyệt danh sách liên kết đến cuối. Node cuối là node có next = NULL
12 }
13 //Gán next của pt cuối = temp. Khi đó temp sẽ là pt cuối(temp->next = NULL mà)
14 p->next = temp; }
15 return head;
16 }

12/09/2021
Danh sách liên kết (5)
n Thêm Node vào danh sách liên kết
¨ Thêm vào vị trí bất kỳ
1 node AddAt(node head, int value, int position){
2 if(position == 0 || head == NULL){
3 head = AddHead(head, value); // Nếu vị trí chèn là 0, tức là thêm vào đầu
4 }else{
5 // Bắt đầu tìm vị trí cần chèn. Ta sẽ dùng k để đếm cho vị trí
6 int k = 1;
7 node p = head;
8 while(p != NULL && k != position){
9 p = p->next;
10 ++k;
11 }
12
13 if(k != position){
14 // Nếu duyệt hết danh sách lk rồi mà vẫn chưa đến vị trí cần chèn, ta sẽ mặc định chèn cuối
15 // Nếu bạn không muốn chèn, hãy thông báo vị trí chèn không hợp lệ
16 head = AddTail(head, value);
17 // printf("Vi tri chen vuot qua vi tri cuoi cung!\n");
18 }else{
19 node temp = CreateNode(value);
20 temp->next = p->next;
21 p->next = temp;
22 }
23 }
24 return head;
25 }
12/09/2021
Danh sách liên kết (6)
n Xóa Node khỏi danh sách liên kết
¨ Xóa đầu

1 node DelHead(node head){


2 if(head == NULL){
3 printf("\nCha co gi de xoa het!");
4 }else{
5 node p = head;
6 head = head->next;
7 delete p;
8 }
return head;
}

12/09/2021
Danh sách liên kết (6)
n Xóa Node khỏi danh sách liên kết
¨ Xóa cuối
1 node DelTail(node head){
2 if (head == NULL || head->next == NULL){
3 return DelHead(head);
4 }
5 node p = head;
6 while(p->next->next != NULL){
7 p = p->next;
8 }
9 node q = p->next;
10 p->next = p->next->next; // Cho next bằng NULL
11 // Hoặc viết p->next = NULL cũng được
12 delete q;
return head;
}
12/09/2021
Danh sách liên kết (7)
n Xóa Node khỏi danh sách liên kết
¨ Xóa ở vị trí bất kỳ

1 node DelAt(node head, int position){


2 if(position == 0 || head == NULL || head->next == NULL){
3 head = DelHead(head); // Nếu vị trí chèn là 0, tức là thêm vào đầu
4 }else{
5 // Bắt đầu tìm vị trí cần chèn. Ta sẽ dùng k để đếm cho vị trí
6 int k = 1;
7 node p = head;
8 while(p->next->next != NULL && k != position){
9 p = p->next;
10 ++k;
11 }
12
13 if(k != position){
14 // Nếu duyệt hết danh sách lk rồi mà vẫn chưa đến vị trí cần chèn, ta sẽ mặc định xóa cuối
15 // Nếu bạn không muốn xóa, hãy thông báo vị trí xóa không hợp lệ
16 head = DelTail(head);
17 // printf("Vi tri xoa vuot qua vi tri cuoi cung!\n");
18 }else{
19 node q = p-next;
20 p->next = p->next->next;
21 delete q;
22 }
23 }
return head;
}
12/09/2021
1 node DelAt(node head, int position){
2 if(position == 0 || head == NULL || head->next == NULL){
3 head = DelHead(head); // Nếu vị trí chèn là 0, tức là thêm vào đầu
4 }else{
5 // Bắt đầu tìm vị trí cần chèn. Ta sẽ dùng k để đếm cho vị trí
6 int k = 1;
7 node p = head;
8 while(p->next->next != NULL && k != position){
9 p = p->next;
10 ++k;
11 }
12
13 if(k != position){
14 // Nếu duyệt hết danh sách lk rồi mà vẫn chưa đến vị trí cần chèn, ta sẽ mặc định xóa cuối
15 // Nếu bạn không muốn xóa, hãy thông báo vị trí xóa không hợp lệ
16 head = DelTail(head);
17 // printf("Vi tri xoa vuot qua vi tri cuoi cung!\n");
18 }else{
19 node q = p-next;
20 p->next = p->next->next;
21 delete q;
22 }
23 }
return head;
}
12/09/2021
Danh sách liên kết (7)
n Lấy giá trị ở vị trí bất kỳ
¨
1 int Get(node head, int index){
2 int k = 0;
3 node p = head;
4 while(p->next != NULL && k != index){
5 ++k;
6 p = p->next;
7 }
8 return p->data;
9 }

12/09/2021
Danh sách liên kết (8)
n Tìm kiếm trong danh sách liên kết
¨ Hàm tìm kiếm này sẽ trả về chỉ số của Node đầu tiên có giá trị
bằng với giá trị cần tìm. Nếu không tìm thấy, chúng ta trả về -1.

1 int Search(node head, int value){


2 int position = 0;
3 for(node p = head; p != NULL; p = p->next){
4 if(p->data == value){
5 return position;
6 }
7 ++position;
8 }
9 return -1;
10 }

12/09/2021
Danh sách liên kết (9)
n Duyệt danh sách liên kết

1 void Traverser(node head){


2 for(node p = head; p != NULL; p = p->next){
3 cout<<setw(5)<< p->data;
4 }
5 cout<<endl;
6 }

n Xoá tất cả các phần tử trong danh sách


1 node DelByVal(node head, int value){
2 int position = Search(head, value);
3 while(position != -1){
4 DelAt(head, position);
5 position = Search(head, value);
6 }
7 return head;
8 }
12/09/2021
Danh sách liên kết (10)
n Một số hàm khác 1 node InitHead(){
¨ Hàm khởi tạo Node head 2 node head;
3 head = NULL;
4 return head;
5 }

¨ Hàm lấy số phần tử của DSLK


1 int Length(node head){
2 int length = 0;
3 for(node p = head; p != NULL; p = p->next){
4 ++length;
5 }
6 return length;
7 }

12/09/2021
Ngăn xếp
n 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.
n Tính chất
¨ Vào trước ra sau (First In Last Out: FILO)

38
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()

39
Ngăn xếp
n Ứng dụng
¨ Trực tiếp
n Nhật trình lướt web lưu trong trình duyệt
n Chuỗi undo trong một trình soạn thảo văn bản

n Việc lưu trữ các biến cục bộ khi một hàm gọi hàm
khác và hàm này lại gọi tới hàm khác nữa, …
¨ Gián tiếp
n Cấu trúc dữ liệu phụ trợ cho các thuật toán
n Một phần của CTDL khác

40
Ngăn xếp
n Ngăn xếp chạy chương trình của
C++
n Hệ thống chạy chương trình của C++
dùng một ngăn xếp để quản lý một
chuỗi các hàm đang thực thi
n Khi một hàm được gọi, hệ này push vào
ngăn xếp một frame chứa:
¨ các biến cục bộ và giá trị trả về
¨ con đếm chương trình (program counter)
để theo dõi câu lệnh đang được thực hiện
n Khi một hàm trả về gì đó, frame của nó
bị pop khỏi ngăn xếp và quyền điều
khiển được chuyển cho hàm ở đỉnh
ngăn xếp.

41
Ngăn xếp
n Cài đặt ngăn xếp
¨ Sử dụng mảng
n 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
n 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)
¨ Sử dụng danh sách liên kết
các nút

t Æ

12/09/2021 các phần tử


Ngăn xếp
n Ứng dụng:
¨ Kiểm tra biểu thức dấu ngoặc cân xứng
n Mỗi ngoặc mở “(“, “[“, “{“ phải được cặp với một
ngoặc đóng “)“, “]“, “}“ tương ứng.
n 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: (

43
Ngăn xếp
n Ứng dụng
n Kiểm tra biểu thức dấu ngoặc cân xứng
¨ Thuật toán
Algorithm ParenMatch(X,n):
Input: An array X of n tokens, each of which is either a grouping symbol, a
variable, an arithmetic operator, or a number
Output: true if and only if all the grouping symbols in X match
Let S be an empty stack
for i=0 to n-1 do
if X[i] is an opening grouping symbol then
S.push(X[i])
else if X[i] is a closing grouping symbol then
if S.isEmpty() then
return false {nothing to match with}
if S.pop() does not match the type of X[i] then
return false {wrong type}
if S.isEmpty() then
return true {every symbol matched}
else
return false {some symbols were never matched}
44
Ngăn xếp
n Ứng dung
¨ Kiểm tra thẻ HTML cân xứng
n Mỗi thẻ mở <name> phải được cặp với một thẻ đóng </name> tương ứng

<body>
<center> The Little Boat
<h1> The Little Boat </h1>
</center>
The storm tossed the little boat
<p> The storm tossed the little
like a cheap sneaker in an old
boat like a cheap sneaker in an
old washing machine. The three washing machine. The three
drunken fishermen were used to drunken fishermen were used to
such treatment, of course, but such treatment, of course, but not
not the tree salesman, who even as the tree salesman, who even as
a stowaway now felt that he a stowaway now felt that he had
had overpaid for the voyage. </p> overpaid for the voyage.
<ol>
<li> Will the salesman die? </li>
<li> What color is the boat? </li> 1. Will the salesman die?
<li> And what about Naomi? </li> 2. What color is the boat?
</ol> 3. And what about Naomi?
45
</body>
Ngăn xếp
n Bài tập
1. Viết chương trình cài đặt ngăn xếp bằng
mảng.
2. Viết chương trình cài đặt ngăn xếp bằng
danh sách liên kết.
3. Với mỗi phép toán trong câu 1, 2 tính độ
phức tạp.
4. Viết chương trình kiểm tra tính hợp lệ các
cặp ngoặc ( ) [ ] { } cho một chương trình
46
C++.
Hàng đợi
n Hàng đợi là gì?
¨ Là một danh sách nhưng các phép toán chỉ được thực hiện ở hai đỉnh của danh
sách. Một đỉnh gọi là đầu hàng, đỉnh còn lại gọi là cuối hàng.
n Tính chất
¨ Vào trước ra trước (First In First Out: FIFO)

47
KDLTT hàng đợi
— Trừu tượng hóa cấu trúc hàng đợi
— Đặc tả dữ liệu
A = (a0, a1, …, an)
trong đó a0 là đầu hàng đợi, an là cuối hàng đợi
— Đặc tả các phép toán
1. Thêm phần tử x vào cuối hàng đợi: enqueue(x)
2. Loại phần tử ở đầu hàng đợi: dequeue()
3. Kiểm tra hàng đợi có rỗng hay không: isEmpty()
4. Kiểm tra hàng đợi hết chỗ hay chưa: isFull()
5. Đếm số phần tử của hàng đợi: size()
6. Trả về phần tử ở đầu hàng đợi: front()

48
Hàng đợi
n Ứng dụng
¨ Trực tiếp
n Danh sách hàng đợi
n Quản lý truy cập tới các tài nguyên dùng chung (ví
dụ máy in)
n Multiprogramming

¨ Gián tiếp
n Cấu trúc dữ liệu phụ trợ cho các thuật toán
n Một phần của CTDL khác

49
Hàng đợi
n Cài đặt hàng đợi bởi mảng
¨ Dùng một mảng cỡ N theo kiểu vòng tròn
¨ Dùng 2 biến để theo dõi đầu (front) và đuôi (rear) hàng đợi
n f là chỉ số của phần tử front

n r là chỉ số của ô liền sau phần tử rear


¨ Ô r trong mảng sẽ luôn rỗng

cấu hình bình thường


Q
0 1 2 f r
cấu hình bọc vòng quanh
Q
0 1 2 r f
50
Hàng đợi
n Các thao tác
¨ Ta sử dụng phép chia lấy dư
Algorithm size()
return (N - f + r) mod N
Algorithm isEmpty()
return (f = r)

Q
0 1 2 f r
Q
0 1 2 r f
51
Hàng đợi
n Các thao tác
¨ Thao tác enqueue ném một ngoại lệ nếu mảng đã đầy
¨ Đây là ngoại lệ do cài đặt

Algorithm enqueue(o)
if size() = N - 1 then
throw FullQueueException
else
Q[r] ¬ o
r ¬ (r + 1) mod N
Q
0 1 2 f r
Q
52
0 1 2 r f
Hàng đợi
n Các thao tác
¨ Thao tác dequeue ném ngoại lệ nếu hàng đợi rỗng
¨ Đây là ngoại lệ xác định cho KDLTT hàng đợi

Algorithm dequeue()
if isEmpty() then
throw EmptyQueueException
else
o ¬ Q[f]
f ¬ (f + 1) mod N
return o
Q
0 1 2 f r
Q
0 1 2 r f
53
Hàng đợi
n Ta có thể cài đặt hàng đợi bởi một danh sách liên kết
đơn
¨ Phần tử front được lưu ở nút đầu
¨ Phần tử rear được lưu ở nút cuối

n Không gian sử dụng là O(n) và mỗi thao tác thực hiện


trong thời gian O(1) r
các nút

t Æ

12/09/2021 các phần tử


Hàng đợi
n Ứng dụng: Lập lịch quay vòng
(Round Robin Schedulers)
n Có thể cài đặt một bộ lập lịch quay vòng bằng một hàng đợi,
Q, bằng việc lặp lại các bước sau:
1. e = Q.dequeue()
2. Service element e
3. Q.enqueue(e)

The Queue

1. Deque the 2. Service the 3. Enqueue the


next element next element serviced element

Shared
Service

55
Bài tập
1. Viết chương trình cài đặt hàng đợi bằng
mảng.
2. Viết chương trình cài đặt hàng đợi bằng
danh sách liên kết đơn.
3. Cài đặt hàng đợi bằng mảng vòng.

56

You might also like