View
303
Download
2
Category
Preview:
Citation preview
Đại Học Sư Phạm Tp. Hồ Chí MinhĐại Học Sư Phạm Tp. Hồ Chí Minh
CẤU TRÚC DỮ LI ỆU 2 CẤU TRÚC DỮ LI ỆU 2
Chương 02: BẢNG BĂM
Đề cương môn học: CTDL2CTDL2
• Chương 1: Sắp xếp ngoại
• Chương 2: Bảng băm (Hash Table)
• Chương 3: B – Cây (B-Tree)
• Chương 4: Cây Đỏ Đen (Red-Black Tree)
22CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
Nội dung
• Giới thiệu bài toán
• Hàm băm
• Các phương pháp xử lý đụng độ
• Phân tích phép băm
33CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
• Phân tích phép băm
ĐẶT VẤN ĐỀ
• Cho S là tập hợp n phần tử trong 1 cấu trúc dữ liệu được đặc trưng bởi 1 giá trị khóa
• Tìm 1 phần tử có hay không trong S– Tìm tuyến tính (O(n)), chưa được sắp xếp
– Tìm nhị phân (O(log n)), đã được sắp xếp
44CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
– Tìm nhị phân (O(log2n)), đã được sắp xếp
• Có hay chăng 1 thuật toán tìm kiếm với O(1)– Có, song ta phải tổ chức lại dữ liệu
– Dữ liệu được tổ chức lại là Bảng băm
Giới thi ệu về Bảng Băm
• Là CTDL trong đó các phần tử của nó được lưu trữsao cho việc tìm kiếm sẽ được thực hiện bằng cáchtruy xuất trực tiếp thông qua từ khóa.
• Bảng băm có M vị trí được đánh chỉ mục từ 0 đến M-1, M là kích thước của bảng băm.
• Các phương pháp băm:
55CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
• Các phương pháp băm:– PP kết nối trực tiếp
– PP kết nối hợp nhất
– PP dò tuyến tính
– PP dò bậc 2
– PP băm kép
Hàm băm
• Hàm băm: biến đổi khóa thành chỉ mục trên bảng băm– Khóa có thể là dạng số hay dạng chuỗi– Chỉ mục được tính từ 0..M-1, với M là số chỉ mục
của bảng băm
66CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
– Hàm băm thường dùng: key % Mkey % M, với M là độ lớn của bảng băm
• Hàm băm tốt phải thoả yêu cầu– Giảm thiểu xung đột– Phân bố đều trên M địa chỉ khác nhau của bảng
băm
Mô tả dữ liệu
• K: tập các khoá (set of keys)
• M: tập các địa chỉ (set of addresses).
• HF(k): hàm băm dùng để ánh xạ một khoá k từ tập các khoá K thành một địa chỉ tương ứng trong tập M. Thông thường HF(k) = k mod M
77CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
M. Thông thường HF(k) = k mod M
Ưu điểm bảng băm
• Dung hòa tốt giữa thời gian truy xuất và dung lượng bộ nhớ– Nếu ko giới hạn bộ nhớ: one-to-one, truy xuất
tức thì
– Nếu dung lượng bộ nhớ có giới hạn thì tổ chức
88CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
– Nếu dung lượng bộ nhớ có giới hạn thì tổ chức khóa cùng địa chỉ
• Bảng băm ứng dụng nhiều trong thực tế, thích hợp tổ chức dữ liệu có kích thước lớn và lưu trữ ngoài.
CÁCH XÂY D ỰNG BẢNG BĂM
– Dùng hàm băm để ánh xạ khóa K vào 1 vị trí trong bảng băm. Vị trí này như là 1 địa chỉ khi tìm kiếm.
– Bảng băm thường là mảng, danh sách liên
99CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
– Bảng băm thường là mảng, danh sách liên kết, file(danh sách đặc)
Ví dụ một bảng băm đơn giản
Khóa k sẽ được lưu trữ tại vị trí k mod M (M kích thước mảng)
0 1 2 3 4 5 6 7 8 9
1010CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
0 1 2 3 4 5 6 7 8 9
95
Thêm phần tử x = 95 vào mảng 95 mod 10 = 5
Ví dụ một bảng băm đơn giản
Với các giá trị: 31, 10, 14, 93, 82, 95,79,18, 27, 46
0 1 2 3 4 5 6 7 8 9
1111CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
0 1 2 3 4 5 6 7 8 9
10 31 82 93 14 95 46 27 18 79
Tìm ki ếm trên bảng băm
• Thao tác cơ bản nhất được cung cấp bởi Hashtable là “tìm kiếm”
• Chi phí tìm kiếm trung bình là O(1), không phụ thuộc vào số lượng phần tử của mảng
1212CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
phụ thuộc vào số lượng phần tử của mảng (Bảng)
• Chi phí tìm kiếm xấu nhất (ít gặp) có thể là O(n)
Các phép toán trên hàm băm
• Khởi tạo (Initialize)• Kiểm tra rỗng (Empty)• Lấy kích thước bảng băm (size)• Thêm 1 phần tử vào bảng băm (Insert)
1313CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
• Thêm 1 phần tử vào bảng băm (Insert)• Xóa 1 phần tử khỏi bảng băm (Remove)• Duyệt (Traverse)
Vấn đề nảy sinh
Giả sử thêm 55vào mảng
0 1 2 3 4 5 6 7 8 982 95 27
1414CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
82 95 27
+ 55phải lưu vào vị trí 5. Tuy nhiên vị trí này đã có chứa 95
k1 ≠ k2 mà f(k1) = f(k2) � Đụng độ=> Cần giải quyết đụng độ (xung đột)đụng độ (xung đột)
- Trong thực tế có nhiều trường hợp có nhiềuhơn 2 phần tử sẽ được “băm” vào cùng 1 vị trí
Vấn đề xung đột khi xử lý bảng băm
1515CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
- Hiển nhiên phần tử được “băm” đầu tiên sẽchiếm lĩnh vị trí đó, các phần tử sau cần phảiđược lưu vào các vị trí tr ống khác sao cho vấnđề truy xu ất và tìm kiếm phải dễ dàng
a. Làm giảm xung đột
-Hàm băm cần thỏa mãn các điều kiện:�Xác xuất phân bố khoá là đều nhau�Dễ dàng tính toán thao tác�Ít xảy ra đụng độ
1616CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
�Ít xảy ra đụng độ
Thông thường, hàm băm sử dụng các số nguyên tố (vì xác suất ngẫu nhiên phân bố các số nguyên tố là đều nhất)
b. Giải quyết xung đột
Các phương pháp băm:�PP kết nối trực tiếp�PP kết nối hợp nhất�PP dò tuyến tính
1717CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
�PP dò tuyến tính�PP dò bậc 2�PP băm kép
i. Sử dụng DS liên kết (kết nối tr ực tiếp)
-Ý tưởng: “Các phần tử băm vào trùng vị trí k được nối vào danh sách nối kết” tại vị trí đó
0 1 2 3 4Hàm băm:
1818CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
0 1 2 3 421 18
Hàm băm:F(k) = k mod 5
Thêm 6, 16 6
16
*Phân tích
PP DSLK có nhiều khuyết điểm:- Khi có quá nhiều khoá vào cùng vị trí,
DSLK thì tại vị trí đó sẽ rất dài => Tăng chi phí tìm kiếm
1919CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
tìm kiếm- Các ô trống còn dư nhiều => lãng phí về
thời gian tìm kiếm và không gian lưu trữ
Cài đặt - Coding
- Sử dụng DSLK tại mỗi vị trí lưu trữ- Nếu xảy ra xung đột thì lưu vào cuối DS
tại vị trí trùng
2020CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
0 1 2 3 421 18
Hàm băm:F(k) = k mod 5
Thêm 6, 16 6
16
CÀI ĐẶT
• Khai báo cấu trúc dữ liệu• Khởi tạo bảng băm• Tạo 1 nút để thêm vào bảng băm• Xác định hàm băm• Thêm 1 nút vào bảng băm
2121CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
• Thêm 1 nút vào bảng băm• Xóa 1 phần tử trong bảng băm• Tìm 1 phần tử trong bảng băm.
Khai báo CTDL
const int M = 101; //Kích thước bảng bămstruct node{
int key;
2222CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
int key;node* next;
};typedef node* LINKLIST ;LINKLIST HashTable[M]; //bảng băm
Khởi tạo bảng bămvoid Init_HashTable(){
for (int i = 0 ; i< M; ++ i)HashTable[i] = NULL;
}
2323CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
}//Xác định hàm bămint Hash(int key){
return (key % M);}
Tạo 1 nút để thêm
//tạo nút có trường dữ liệu là x, hàm trả về địa chỉ của node mới tạo.
node* GetNode(int x){
node *pnew = new node;
2424CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
node *pnew = new node;pnew->key = x;pnew->next = NULL;return pnew;
}
Ki ểm tra bảng băm rỗng?
bool Empty(){
for(int b = 0; b < M; b++)if(HashTable[b] != NULL)
2525CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
if(HashTable[b] != NULL)return false;
return true;}
Hàm xuất bảng bămvoid PrintHT(){
node *p;for(int i=0;i<M;i++){
cout<<"Bucket "<<i<<": ";
2626CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
cout<<"Bucket "<<i<<": ";p = HashTable[i];while(p!=NULL){
cout<<“ � “<<p->key;p = p->next;
}cout<<endl;
}}
Thêm một khoá vào bảng băm//Chèn một khoá vào bảng bămvoid Insert(int k){
InsertTail_LINKLIST(HashTable[Hash(k)], k);}//Chèn cuối danh sáchvoid InsertTail_LINKLIST(LINKLIST &l, int k){
2727CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
{//Tạo nodenode *add = GetNode(k);if (l == NULL) l = add;else{
node * p = l;while (p->next != NULL) p = p->next;p->next = add;
}}
Xoá một khoá trong bảng băm
//Hàm xóa 1 phần tử có khóa keyvoid Delete(int key){
Delete_LINKLIST(HashTable[Hash(key)], key);}
2828CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
}
Xoá một khoá trong bảng bămvoid Delete_LINKLIST(LINKLIST &l, int key){
node *p = l, *q = NULL;if(p == NULL) //DS rong
cout<<endl<<"Khong tim thay - DS rong!"<<endl;else //tim thay{
2929CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
{if(p->key==key)//Nam dau danh sach{
l = p->next;delete p;cout<<endl<<"Da xoa!"<<endl;
}
Xoá một khoá trong bảng bămelse{
while((p != NULL)&&(p->key != key)){
q = p; p = p->next;}if(p != NULL) //tim thay{
3030CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
{q->next = p->next;delete p;cout<<endl<<"Da xoa!"<<endl<<endl;
}else
cout<<"KQ: Khong tim thay"<<endl;}
}}
Tìm một phần tử
// tim 1 phan tu co khoa =key trong bang bamnode* Search(int x){ int i = Hash(x);
node* p = HashTable[i];if(p != NULL){
3131CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
{while((p != NULL)&&(p->key != x))
p = p->next;}return p;
}
Hàm tạo menu chương trìnhvoid menu(){
puts("DEMO HASHTABLE dung DSLK");puts("1. Them 1 phan tu vao bang bam");puts("2. Xoa 1 phan tu trong bang bam");
3232CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
puts("2. Xoa 1 phan tu trong bang bam");puts("3. Tim 1 phan tu co khoa x");puts("4. Xuat Hash Table");puts("0. Ket thuc");
}
Chương trình chính
int main(){
int chon, x;Init_HashTalbe();//khoi tao bang bamdo
3333CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
do{ menu();
cout<<"Chon chuc nang: ";cin>>chon;cout<<endl;
Chương trình chínhswitch(chon){
case 1:do{
cout<<"Nhap khoa can them: "; cin>>x;if(x > 0) Insert(x);
3434CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
if(x > 0) Insert(x);}while(x > 0);break;
case 2:cout<<"Nhap khoa can xoa (key > 0): ";cin>>x;if(x > 0) Delete(x);break;
Chương trình chínhcase 3:
cout<<"Nhap khoa can tim (key > 0): ";cin>>x;if(x > 0){
if(Search(x) != NULL)cout<<"Tim thay “<<x;
else
3535CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
elsecout<<"Tim khong thay";
}break;
case 4: PrintHT(); break;}
}while(chon != 0);return 0;
}
ii. Sử dụng PP “kết nối hợp nhất”
-Ý tưởng: “Nếu có 1 khóa bị băm vào vị trí đã có phần tử thì nó sẽ được chèn vào ô trống phía cuối mảng”. (Dùng mảng có M phần tử)
0
3636CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
Hàm băm:F(k) = k mod 5Thêm
6, 16
0
1 21
2
3 18
4 6
16
iii. Sử dụng PP “Dò tuyến tính”
-Ý tưởng: “Nếu có 1 khóa bị băm vào vị trí đã có phần tử thì nó sẽ được chèn vào ô trống gần nhất” theo phía bên phải (hoặc trái)
0 1 2 3 4Hàm băm:
3737CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
0 1 2 3 421 18
Hàm băm:F(k) = k mod 5
Thêm 6, 16
6 16
f(key)=(f(key)+i) % M với f(key) là hàm băm chính của bảng băm.
*Phân tích
- PP này dễ thực hiện- Nếu có nhiều phần tử băm trùng nhau thì
đặc tính bảng băm bị mất đi- Trong trường hợp xấu nhất tìm kiếm trên
3838CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
- Trong trường hợp xấu nhất tìm kiếm trên bảng băm thành tìm kiếm tuyến tính trên mảng
Cài đặt
-Khi xảy ra đụng độ thì chèn vào vị trí trống gần nhất- Ví dụ: chèn dãy: 5 16 7 8 2 4 6 3 13 24 vào mãng băm có 11 vị trí
3939CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
vào mãng băm có 11 vị trí
0 1 2 3 4 5 6 7 8 9 10
24 2 3 4 5 16 7 8 6 13
code
const int M = 101; //Kich thuoc bảng băm
int HashTable[M]; //bảng băm
4040CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
Khởi tạo bảng băm
void Init_HashTalbe(){
for (int i = 0 ; i< M; ++ i)HashTalbe[i] = -1 ;
4141CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
HashTalbe[i] = -1 ;}
Ki ểm tra bảng băng rỗng?
bool Empty(){
for(int b = 0; b < M; b++)if(HashTable[i] != -1)
4242CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
if(HashTable[i] != -1)return false;
return true;}
Thêm một khoá vào bảng bămvoid Insert(int k){
//Xác định vị trí của khoá kint pos = Hash(key)//Kiểm tra đảm bảo vị trí pos là trốngwhile (HashTable[pos] != -1 )
4343CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
while (HashTable[pos] != -1 ){
pos = Hash (pos + 1);//Kiểm tra full
}
HashTable[pos] = key;}
Xoá một khoá trong bảng băm
int Delete(int key){
int pos = Hash(key); count = 1;while (HashTable[pos] != key){
pos = Hash(pos + 1 );count ++;
4444CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
count ++;if (count > M) break;
} if (count <= M){ HashTable[pos] = -1; return 1;}
return 0; //không tìm được khoá
}
iv. Sử dụng PP “Dò bậc hai”
0 1 2 3 4Hàm băm:
f(key)=(f(key) + i 2) % Mvới f(key) là hàm băm chính của bảng băm.
4545CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
0 1 2 3 421 18
Hàm băm:F(k) = k mod 5
Thêm 6, 16
616
iv. Sử dụng PP “Băm kép”
Ta sử dụng 2 hàm băm:f1(key)= key % Mf2(key)= (M–2) – key % (M-2)
4646CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
f2(key)= (M–2) – key % (M-2)
Cài đặt – Băm kép (Double Hashing)
-Dò tuyến tính: pos = (pos + 1) % M
4747CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
-Dò tuyến tính: pos = (pos + 1) % M- Băm kép: pos = (pos + u) % M
u = Hash2 (key)
code
const int M = 101; //Kich thuoc bảng băm
int HashTable[M]; //bảng băm
4848CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
Khởi tạo bảng băm
void Init_HashTalbe(){
for (int i = 0 ; i< M; ++ i)HashTalbe[i] = -1 ;
4949CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
HashTalbe[i] = -1 ;}
2 Hàm băm
int Hash(int key){
return key % M}
5050CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
int Hash2(int key){
return (M-2) – key % (M-2);}
Thêm một khoá vào bảng bămvoid Insert(int k){ //Xác định vị trí của khoá k
int pos = Hash(key)//Kiểm tra đảm bảo vị trí pos là trốngwhile (HashTable[pos] != -1 ){
int u = Hash2 (key);
5151CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
int u = Hash2 (key);pos = (pos + u ) % M;//Kiểm tra full
}
HashTable[pos] = key;}
Bài tập
Viết chương trình hiện thực từ điển Anh - Việt. Mỗi nút của bảng băm có khai báo các trường sau:– Trường word là khoá chứa một từ tiếng anh.– Trường mean là nghĩa tiếng Việt.– Trường next là con trỏ chỉ nút kế nếu bị xung đột.
Tập khoá là một chuỗi tiếng anh, tập địa chỉ có 26 chữ cái. Chọn hàm băm sau cho khoá bắt đầu bằng ký tự a được băm
5252CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
Chọn hàm băm sau cho khoá bắt đầu bằng ký tự a được băm vào địa chỉ 0, b băm vào địa chỉ 1,…, z băm vào địa chỉ 25. Chương trình có những chức năng như sau:1. Nhập vào một từ2. Xem từ điển theo ký tự đầu.3. Xem toàn bộ từ điển.4. Tra từ điển.5. Xoá một từ, xóa toàn bộ từ điển.
Câu hỏi và thảo luận
5353CTDL2 – Lương Trần Hy HiếnLương Trần Hy Hiến
Recommended