1. 程式人生 > >雜湊查詢演算法及C語言實現

雜湊查詢演算法及C語言實現

上一節介紹了有關雜湊表及其構造過程的相關知識,本節將介紹如何利用雜湊表實現查詢操作。

在雜湊表中進行查詢的操作同雜湊表的構建過程類似,其具體實現思路為:對於給定的關鍵字 K,將其帶入雜湊函式中,求得與該關鍵字對應的資料的雜湊地址,如果該地址中沒有資料,則證明該查詢表中沒有儲存該資料,查詢失敗:如果雜湊地址中有資料,就需要做進一步的證明(排除衝突的影響),找到該資料對應的關鍵字同 K 進行比對,如果相等,則查詢成功;反之,如果不相等,說明在構造雜湊表時發生了衝突,需要根據構造表時設定的處理衝突的方法找到下一個地址,同地址中的資料進行比對,直至遇到地址中資料為 NULL(說明查詢失敗),或者比對成功。

回顧:雜湊表在構造過程中,處理衝突的方法有:開放定址法、再雜湊法、鏈地址法、建立公共溢位區法。

假設雜湊表在構造過程採用的開放定址法處理的衝突,則雜湊表的查詢過程用程式碼實現為:
#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

查詢演算法的效率分析

在構造雜湊表的過程中,由於衝突的產生,使得雜湊表的查詢演算法仍然會涉及到比較的過程,因此對於雜湊表的查詢效率仍需以平均查詢長度來衡量。

在雜湊表的查詢過程中需和給定值進行比較的關鍵字的個數取決於以下 3 個因素:
  • 雜湊函式:雜湊函式的“好壞”取決於影響出現衝突的頻繁程度。但是一般情況下,雜湊函式相比於後兩種的影響,可以忽略不計。
  • 處理衝突的方式:對於同一組關鍵字,設定相同的雜湊函式,使用不同的處理衝突的方式得到的雜湊表是不同的,表的平均查詢長度也不同。
  • 雜湊表的裝填因子:在一般情況下,當處理衝突的方式相同的情況下,其平均查詢長度取決於雜湊表的裝滿程度:裝的越滿,插入資料時越有可能發生衝突;反之則越小。

裝填因子=雜湊表中資料的個數/雜湊表的長度,用字元 α 表示(是數學符號,而不是字元 a)。裝填因子越小,表示雜湊表中空閒的位置就越多。

經過計算,在假設查詢表中的所有資料的查詢概率相等的情況下,對於表長為 m,資料個數為 n 的雜湊表:
  • 其查詢成功的平均查詢長度約為:-1/α * ln⁡(1-α)
  • 其查詢不成功的平均查詢長度約為:1/(1-α)
通過公式可以看到,雜湊表的查詢效率只同裝填因子有關,而同雜湊表中的資料的個數無關,所以在選用雜湊表做查詢操作時,選擇一個合適的裝填因子是非常有必要的。