Mảng băm là một cấu trúc dữ liệu ánh xạ từ khóa tới dữ liệu. Trong mảng băm các khóa luôn luôn khác nhau. Hàm băm là là hàm số chuyển từ khóa thành giá trị băm tương ứng trong mảng lưu trữ các giá trị cần tìm.
Trong trường hợp lý tưởng thì một hàm băm sẽ luôn chuyển đổi khóa khác nhau thành các giá trị băm khác nhau. Tuy nhiên trong thực tế, các thuật toán băm luôn cung cấp cách giải quyết khi các khóa khác nhau lại băm về cùng một giá trị (hay còn gọi là va chạm băm).
Khi bảng băm có kích thước đủ lớn, thời gian trung bình để tra cứu một phần tử là hằng số O(1), không phụ thuộc vào số lượng phần tử trong bảng băm.
Ví dụ
Sau đây là cách cài đặt mảng băm đơn giản trong C. Ở ví dụ này, chúng ta có danh sách mảng với dữ liệu cần thêm vào bảng băm bao gồm số điện thoại (6 số cuối) và tên. Mảng băm là một mảng lưu các 10 địa chỉ. Hàm băm của chúng ta là lấy số điện thoại chuyển thành số nguyên rồi chia lấy dư cho 11.
typedefstructData{intphoneNumber;charname[10];}Data;typedefstructHashTable{Data**dataArray;}HashTable;intmain(){constintSIZE_ARRAY=10;HashTableht;// cấp phát bộ nhớ
ht.dataArray=(Data**)malloc(sizeof(Data*)*SIZE_ARRAY);// khởi tạo giá trị NULL
for(inti=0;i<SIZE_ARRAY;i++){ht.dataArray[i]=NULL;}Dataperson1={.phoneNumber=124565,.name="Tung"};Dataperson2={.phoneNumber=672922,.name="Vuong"};Dataperson3={.phoneNumber=926505,.name="Hoa"};}
Hàm thêm giá trị vào hàm băm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
voidaddToHashTable(HashTable*hashTable,Data*data){intkey=data->phoneNumber%11;// hàm băm
Data*node=(Data*)malloc(sizeof(Data));node->phoneNumber=data->phoneNumber;// copy phoneNumber
strcpy(node->name,data->name);// copy name
hashTable->dataArray[key]=node;}intmain(){addToHashTable(&ht,&person1);addToHashTable(&ht,&person2);addToHashTable(&ht,&person3);}
Kiểm tra giá trị với key
Với hàm băm và key ta tìm được giá trị băm. Sử dụng giá trị băm và key ta có thể tìm được giá trị cần tìm.
Có hai cách giải quyết va chạm đó là phương pháp kết nối và phương pháp địa chỉ mở. Phương pháp kết nối lưu các giá trị vào một danh sách liên kết. Còn phương pháp địa chỉ mở thì các cặp vạ chạm khóa-giá trị được lưu trong bảng ở một chỗ khác. Một thuật toán sẽ tìm vị trí tiếp theo của của khóa va chạm này.
Trong ví dụ trên các khóa khi được băm ra sẽ có các giá trị khác nhau. Giờ ta sẽ giải quyết trường hợp va chạm với ví dụ trên khi thêm hai dữ liệu mới như sau:
Số điện thoại
Tên
Giá trị băm
124565
Tung
1
672922
Vuong
8
926506
Hoa
9
284657
Mai
10
228306
Linh
1
Có va chạm với số điện thoại 124565, tên Tung ở trên khi cùng giá trị băm là 1. Cách cài đặt giải quyết va chạm khi sử dụng danh sách liên kết như sau:
typedefstructData{intphoneNumber;charname[10];structData*next;}Data;voidaddToHashTable(HashTable*hashTable,Data*data){intkey=data->phoneNumber%11;// hàm băm
Data*newData=malloc(sizeof(Data));// tạo dữ liệu mới
newData->phoneNumber=data->phoneNumber;// copy phoneNumber
strcpy(newData->name,data->name);// copy name
// tạo danh sách liên kết
newData->next=hashTable->dataArray[key];hashTable->dataArray[key]=newData;}Data*findData(HashTable*hashTable,intphoneNumber){intkey=phoneNumber%11;// hàm băm
Data*data=hashTable->dataArray[key];// lấy data
// lặp qua danh sách liên kết
while(data!=NULL){// nếu trùng phoneNumber thì return
if(data->phoneNumber==phoneNumber){returndata;}data=data->next;}returnNULL;}voiddeleleData(HashTable*hashTable,intphoneNumber){intkey=phoneNumber%11;Data*node=hashTable->dataArray[key];if(node==NULL){return;}if(node->phoneNumber==phoneNumber){free(node);hashTable->dataArray[key]=NULL;return;}Data*preNode=node;preNode=node;node=node->next;// lặp qua danh sách liên kết
while(node!=NULL){// nếu trùng phoneNumber thì xóa phần tử đó
if(node->phoneNumber==phoneNumber){preNode->next=node->next;free(node);return;}preNode=node;node=node->next;}}
Trên đây là ví dụ để minh họa việc sử dụng hashmap. Trong thực tế chúng ta sẽ thường sử dụng hashmap qua các thư viện được viết sẵn.