Professional Documents
Culture Documents
Lớp : KTĐT-VT
Khoá : 62
#include <iostream.h>
#include <conio.h>
void duplicate (int& a, int& b, int& c)
{ a = 2; b = 2; c = 2; }
int main (){
int x=1, y=3, z=7;
duplicate (x, y, z);
cout << "x=" << x << ", y=" << y << ", z=" << z;
return 0;
}
• Có thể sử dụng thêm con trỏ đuôi tail để các thao tác trên DSLK được thuận lợi
• Danh sách rỗng: head = tail = NULL;
- Trong đó:
o h được gọi là hàm băm (hash function)
o K là tập giá trị khóa
o 0..m-1 là bảng địa chỉ (là các số nguyên)
o m là kích thước của bảng
- Yêu cầu khi xây dựng hàm băm:
o Hàm phải dải đều các địa chỉ trên bảng địa chỉ
o Hàm băm phải được tính toán đơn giản.
b. Một số phương pháp xây dựng hàm băm
- Phương pháp chia
o Để tính địa chỉ dải của đối tượng ta lấy giá trị khóa chia cho kích
thước của bảng. Địa chỉ dải là phần dư của phép chia đó.
H(K) = K % m
o Yêu cầu:
hàm h phải dải đều các đối tượng trên bảng một cách ngẫu
nhiên. Để có được điều đó h phải phụ thuộc vào m.
Phụ thuộc vào m
Thông thường người ta chọn m là một số nguyên tố nhỏ hơn
gần với (10,100, 1000,...) nhất.
- Phương pháp nhân
o Giá trị khóa được phân ra thành nhiều đoạn bằng nhau
Người ta sử dụng hai kỹ thuật phân đoạn sau đây:
Tách: Tách các đoạn ra và mỗi đoạn được xếp thành một
hàng, dóng lề trái hoặc lề phải.
Gấp: Gấp các đoạn lại theo đường biên tương tự như gấp giấy,
các chữ rơi vào cùng một chỗ được đặt thành hàng thẳng
nhau.
c. Bảng băm - Hash table
- Một bảng băm là một cấu trúc dựa trên mảng để lưu trữ các phần tử, mỗi
phần tử là một cặp Khóa-Giá trị (key-value)
- Các thành phần cấu thanh lên bảng băm:
o Mảng chứa
o Mỗi phần tử mảng quản lý một danh sách các phần tử có khóa qua
ánh xạ h cho cùng một địa chỉ.
o Hàm băm h(k) - Hash function, h(k)
o Mã băm
EX: Giả sử có hàm h(k) = k % 5 Có các giá trị: 11, 21, 44, 23, 41, 4, 34, 12
Output:
Dãy các phần tử được sắp theo thứ tự tăng hoặc giảm dần theo một hoặc
một vài thuộc tính của nó (các thuộc tính này gọi là thuộc tính khóa).
Thuộc tính khóa được sắp xếp theo một hàm logic, ví dụ (<=) hoặc các toán
tử so sánh khác.
Các thuật toán với thời gian chạy O(n2)
Nổi bọt – Bubble sort
Chèn – Insertion sort
Chọn – Selection sort
Sắp xếp nổi bọt – Bubble sort
Ý tưởng: Thực hiện chuyển dần các phần tử có giá trị khóa lớn về cuối dãy,
các phần tử có khóa bé về đầu dãy.
Thuật toán
- Trong đó swap là thủ tục tráo đổi vị trí của hai phần tử
void Swap(object &a, object &b){
Object tg;
tg = a;a = b; b = tg;
}
Sắp xếp chọn - Selection sort
• Ý tưởng: Chọn phần tử có khóa nhỏ nhất trong các phần tử còn lại chuyển nó về
đầu và loại bỏ nó khỏi dãy.
10
Chia và trị - Divide and conquer
Chia và trị là phương pháp thiết kế thuật toán theo kiểu:
Phân chia: Chia dữ liệu đầu vào S của bài toán thành 2 tập con rời nhau S1
và S2
Đệ qui: Giải bài toán với dữ liệu vào là các tập con S1 và S2
Trị: kết hợp các kết quả của S1 và S2 thành kết quả của S
Trường hợp cơ sở cho thuật toán đệ qui ở đây là các bài toán có kích thước 0 hoặc
1
Sắp xếp nhanh – Quick sort
Ý tưởng (sử dụng phương pháp chia và trị):
Thực hiện phân hoạch dãy S cần sắp thành 3 dãy S1, S2, S3. Trong đó:
• S2 chỉ có một phần tử
• Tất cả các phần tử của dãy S3 đều > phần tử của dãy S2.
• Tất cả các phần tử của dãy S1 đều ≤ phần tử của dãy S2
• Dãy S1, S3 có thể là rỗng
Tiếp tục phân hoạch dãy S1 và S3 độc lập theo nguyên tắc trên đến khi dãy
cần thực hiện phân hoạch chỉ có một phần tử thì dưng lại. Khi đó ta được
dãy các phần tử được sắp.
Thuật toán sắp xếp Quick sort
Từ ý tưởng của thuật toán, ta có thể dễ dàng xây dựng thuật toán sắp xếp dưới
dạng đệ qui như sau:
Algorithm QuickSort (array A, i, j );
Input: Dãy các phần tử A[i],..,A[j] và hai số nguyên i, j
Output: Dãy A[i],..,A[j] được sắp.
if i < j then
Partition (A,i, j, k); //k lấy chỉ số của phần tử làm S2
Quicksort (A,i, k-1);
Quicksort (A,k+1, j);
Thuật toán phân hoạch
• Chọn một phần tử bất kỳ của dãy làm dãy S2 (phần tử này được gọi là phần tử chốt
-pivot).
• Thực hiện chuyển các phần tử có khóa ≤ phần tử chốt về bên trái và các phần tử >
phần tử chốt về bên phải, sau đó đặt phần tử chốt về đúng vị trí của nó trong dãy.
Chú ý :
• Phần tử chốt có thể được chọn là một phần tử bất kỳ của dãy.
- Phần tử chốt có thể chọn là phần tử đầu hoặc giữa hoặc cuối dãy.
- Tốt nhất là chọn phần tử chốt mà nó làm cho việc phân hoạch thành hai dãy S1 và
S3 có số phần tử xấp xỉ bằng nhau.
Thuật toán
• Phân hoạch dãy gồm các phần tử A[i],..,A[j]
• Chọn phần tử đầu dãy làm chốt
• Sử dụng 2 biến left và right:
- left chạy từ trái sang phải bắt đầu từ i.
- right chạy từ phải sang trái bắt đầu từ j
- Biến left được tăng cho tới khi A[left].Key> A[i].Key hoặc
left >right
- Biến right được giảm cho tới khi A[right].Key <= A[i] .Key
- Nếu left< right thì ta đổi A[left] và A[right]
- Quá trình trên được lặp lại cho tới khi nào left > right
- Cuối cùng tráo đổi A[i] và A[right]
Thuật toán phân hoạch
Algorithm Partition (Array A, i, j, &right )
Input: Dãy các phần tử A[i],..,A[j], 2 số nguyên i, j
Output: Dãy A[i],..,A[j] được phân hoạch, right là chỉ số của
phần tử làm S2.
p A[i];
left i; right j;
while ( left < right )
while( A[left].Key <= p.Key && left≤right)
left left+1;
while( A[right].Key > p.Key ) right right-1;
if left < right then
SWAP(A[left],A[right]);
if i<> right then
A[i] A[right];
A[right] p;
Thời gian chạy
• Thủ tục partition kiểm tra tất cả các phần tử trong mảng nhiều nhất một lần, vì vậy
nó mất thời gian tối đa là O(n).
• Thủ tục partition sẽ chia phần mảng được sắp thành 2 phần.
• Mặt khác cần chia liên tiêp n phần tử thành hai phần thì số lần chia nhiều nhất là
log2n lần.
• Vậy thời gian chạy của thuật toán QuickSort là O(nlogn)
CHƯƠNG 7: VECTOR
I. Khái niệm về vector
- Vector là một mảng động có thể thay đổi kích thước,không nhất thiết phải khai
báo kích thước cố định như mảng tĩnh.Nó có thể tự động tăng hay giảm kích
thước khi ta xóa hoặc chèn phần tử khác vào vector
a. Preorder (tiền thứ tự) : Gốc rồi đến các cây con
- Duyệt cây là cách đi thăm các nút của cây theo một hệ thống
- Duyệt theo thứ tự trước, tức là: nút cha được thăm trước sau đó thăm các nút
con, cháu, …
Algorithm preOrder(v)
If(v!=null)
visit(v)
preorder (w)
b. Inorder (trung thứ tự) : Con cả đến Gốc rồi các con còn lại
- Duyệt theo thứ tự giữa, tức là: nút con được thăm trước sau đó thăm nút cha
- Ứng dụng: Tính toán không gian sử dụng bởi các files và
các thư mục con
Algorithm inOrder(v)
If(v!=null)
w = con cả của v
inOrder(w)
visit(v)
for mỗi nút con w1#w của v
inOrder (w1)
Algorithm postOrder(v)
If(v!=null)
postOrder (w)
visit(v)
PHẦN II: Chương tình quản lý thư viện bằng ngôn ngữ
C++
MỤC ĐÍCH : Nhóm chọn đề tài này vì nó thể hiện được gần hết những thứ đã
được học trong môn cấu trúc dữ liệu
Giao diện chương trình
int k;
char ma[80];
cin.getline(ma, sizeof(k));
cout << "Ma ban doc : ";
cin.getline(ma, sizeof(ma));
char ten[80];
cout << "Ten ban doc : ";
cin.getline(ten, sizeof(ten));
cacbandoc[sobandoc++] = new bandoc(ma, ten);
cout << " Ban doc " << ten << " voi ma so la "<<
ma << " da duoc dang ki "<<endl;
- Lệnh tìm bạn đọc : thực hiện cấu trúc tìm kiếm tuần tự (sequence
search):
for (int i = 0; i < sobandoc; i++)
if (strcmp(ma, cacbandoc[i]->ma) == 0)
return cacbandoc[i];
return 0;
- Lênh xóa bạn đọc: thực hiện viện xóa bạn đọc
for (int i = 0; i < sobandoc; i++)
delete[] cacbandoc[i];
sobandoc = 0;
- Lệnh sắp xếp các bạn đọc :
o Sử dụng thuật toán sắp xếp nổi bọt để sắp xếp các bạn đọc giảm dẫn
theo số sách đã mượn
o In ra bảng biểu diễn các bạn đọc theo danh sách đã sắp xếp .
if (sobandoc==0){
cout<<"khong co ban doc nao trong thu vien"<<endl;
}
else {
cout<<"Danh sach cac ban doc muon nhieu nhat: "<<endl;
for (int i=0;i<sobandoc-2;i++){
for (int j =sobandoc; j>i; j--){
if (cacbandoc[i]->somuon < cacbandoc[j-1]->somuon){
swap(cacbandoc[i]->somuon, cacbandoc[j-1]->somuon);
}
}
}
cout<<left<<setw(20)<<"Ma"<<left<<setw(20)<<"Ten"<<left<<setw(20)<<"Somuon"<<endl;
cout << "------------------------------------------------------------"<<endl;
for (int i = 0; i < sobandoc; i++)
cout << left<<setw(20)<<cacbandoc[i]->ma << left<<setw(20)<<
cacbandoc[i]->ten<< left<<setw(20)<< cacbandoc[i]->somuon <<endl;
}
}
- Lệnh nhập sách vào kho:
o Nhập mã sách , gán vào biến ma đã khai báo
o Nhập tên sách , gán vào biến ten đã khai báo
o Nhập số đầu sách sách , gán vào biến n đã khai báo
int h;
char ma[80];
cin.getline(ma, sizeof(h));
cout << "Ma sach :";
cin.getline(ma, sizeof(ma));
char ten[80];
cout << "Ten sach : ";
cin.getline(ten, sizeof(ten));
int n;
cout << "So dau sach : ";
cin >> n;
cin.ignore(1);
khosach[sosach++] = new sach(ma, ten, n);
cout << "Sach nay da duoc nhap vao \n";
- Lệnh in ra danh sách các sách: in ra các cuốn sách có (tên sách, mã sách
và số đầu sách còn lai trong kho)
cout << left<< setw(20)<< "Ma sach"<<left<<setw(20)<<"Ten
sach"<<left<<setw(20)<<"so dau sach"<<endl;
cout<<"-------------------------------------------------------------"<<endl;
for (int i = 0; i < sosach; i++){
cout <<left<<setw(20)<< khosach[i]->ma << left<<setw(20) <<
khosach[i]->ten <<left<<setw(20)<< khosach[i]->sodausach<<endl;
- Lệnh mượn sách:
o Nhập mã bạn đọc muốn mượn, gán với biến mabd đã khai báo
o Nhập mã sách muốn mượn, gán với biến mas đã khai báo
char mabd[80];
cin.getline(mabd, sizeof(k));
cout << "Ma ban doc : ";
cin.getline(mabd, sizeof(mabd));
bandoc* bd = bandoc::timbd(mabd);
if (bd == 0)
{
cout << "Ma ban doc nay chua duoc dang ki \n ";
return;
}
char mas[80];
cout << "Ma sach muon : ";
cin.getline(mas, sizeof(mas));
bd->muon(mas);