雜湊表
雜湊表可以通過關鍵字直接找到資料的儲存位置,其查詢效率也相對較高。
雜湊表的構造
例如,這裡有一個電話簿(查詢表),電話簿中有 4 個人的聯絡方式:
張三 13912345678
李四 15823457890
王五 13409872338
趙六 13805834722
假如想查詢李四的電話號碼,對於一般的查詢方式最先想到的是從頭遍歷,一一比較。而如果將電話簿構建成一張雜湊表,可以直接通過名字“李四”直接找到電話號碼在表中的位置。
在構建雜湊表時,最重要的是雜湊函式的設計。例如設計電話簿案例中的雜湊函式為:每個名字的姓的首字母的 ASCII 值即為對應的電話號碼的儲存位置。這時會發現,張三和趙六兩個關鍵字的姓的首字母都是 Z ,最終求出的電話號碼的儲存位置相同,這種現象稱為衝突。在設計雜湊函式時,要儘量地避免衝突現象的發生。 對於雜湊表而言,衝突只能儘可能地少,無法完全避免。
雜湊函式的構造
常用的雜湊函式構造方法有六種: 直接定址法、數字分析法、平方取中法、摺疊法、除留餘數法和隨機法
除留餘數法(這裡只介紹一種方法,其餘的方法想了解的夥伴可自行谷歌百度)
若已知整個雜湊表的最大長度m,可以取一個不大於m的數p,然後對該關鍵字key做取餘運算。如: key = key % p
處理衝突的方法
對於雜湊表的建立,需要採取合適的雜湊函式,但是對於無法避免的衝突,需要採取適當的措施去處理。
常用的處理衝突的方法有幾種:: 開放定址法、再雜湊法、鏈地址法、建立一個公共溢位區
開放地址法
開放地址法也有三種方法,這裡介紹第一種:線性探測法(線上性探測法中,當遇到衝突時,從發生衝突位置起,每次 +1,向右探測)
例如,在長度為 11 的雜湊表中已填寫好 17、60 和 29 這 3 個資料(如,其中採用的雜湊函式為:key=key%11,現有第4個資料38,當通過雜湊函式求得的雜湊地址為 5,與 60 衝突,於是使用線性探測法 key=(++key)%m;
程式碼實現
#include <stdio.h>
#include <stdlib.h>
#define HASHSIZE 7 //定義雜湊表長為陣列的長度
#define NULLKEY -1
typedef struct{
int *elem;//資料元素儲存地址,動態分配陣列
int count; //當前資料元素個數
}HashTable;
複製程式碼
初始化雜湊表
void Init(HashTable *hashTable){
int i;
hashTable->elem= (int *)malloc(HASHSIZE*sizeof(int));
hashTable->count=HASHSIZE;
for (i=0;i<HASHSIZE;i++){
hashTable->elem[i]=NULLKEY;
}
}
複製程式碼
雜湊函式(除留餘數法)
int Hash(int data){
return data%HASHSIZE;
}
複製程式碼
插入函式
void Insert(HashTable *hashTable,int data){
int hashAddress=Hash(data); //求雜湊地址
//發生衝突
while(hashTable->elem[hashAddress]!=NULLKEY){
//利用開放定址法解決衝突
hashAddress=(++hashAddress)%HASHSIZE;
}
hashTable->elem[hashAddress]=data;
}
複製程式碼
雜湊表的查詢演算法
int Search(HashTable *hashTable,int data){
int hashAddress=Hash(data); //求雜湊地址
while(hashTable->elem[hashAddress]!=data){//發生衝突
//利用開放定址法解決衝突
hashAddress=(++hashAddress)%HASHSIZE;
//如果查詢到的地址中資料為NULL,或者經過一圈的遍歷回到原位置,則查詢失敗
if (hashTable->elem[hashAddress]==NULLKEY||hashAddress==Hash(data)){
return -1;
}
}
return hashAddress;
}
複製程式碼
主函式
int main(){
int i,result;
HashTable hashTable;
int arr[HASHSIZE]={13,29,27,28,26,30,38};
//初始化雜湊表
Init(&hashTable); //引用
//利用插入函式構造雜湊表
for (i=0;i<HASHSIZE;i++){
Insert(&hashTable,arr[i]);
}
//呼叫查詢演算法
result= Search(&hashTable,29);//引用
if (result == -1) {
printf("查詢失敗");
} else {
printf("29在雜湊表中的位置是:%d",result+1);
}
return 0;
}
複製程式碼
執行結果
29在雜湊表中的位置是:2