雜湊查詢演算法

小天秤發表於2018-10-13

雜湊表

雜湊表可以通過關鍵字直接找到資料的儲存位置,其查詢效率也相對較高。

雜湊表的構造

例如,這裡有一個電話簿(查詢表),電話簿中有 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

相關文章