哈希表及其經常使用算法(代碼實例)

<hash表的特性>算法

    Hash 表是使用 O(1) 時間進行數據的插入刪除和查找,可是 hash 表不保證表中數據的有序性,這樣在 hash 表中查找最大數據或者最小數據的時間是 O(N) 。數據結構

<尋址和 hash 函數>

    理想狀態下 hash 足夠大,每一數據保存在一個 hash 存儲單元內,這樣對於插入刪除和查找某一個數據就能夠直接獲得。可是現實狀況下 hash 表不可能無限大,並且理論上保存的數據的個數是沒有限制的,這樣保存的數據的數量就遠遠大於 hash 表的存儲單元的數量。函數

    爲了實如今 O(1) 內對數據進行插入刪除和查找,就必須將一個數據映射到 hash 表中的固定位置,這個映射函數就是 hash 函數。 Hash 函數經過對數據進行計算獲得一個在 hash 表中的位置地址。oop

 

   圖 1.1 理想的 hash 表大數據

      要選擇較好的 hash 函數,以及 hash 表存儲單元的數量,這樣才能使保存在 hash 表中的數據均勻分佈。理想狀態不太可能實現,因爲存儲的數據數量遠遠大於 hash 表存儲單元的數量,因此再好的 hash 函數也可能使不一樣的數據獲得相同的映射位置,這就形成了衝突。可是好的 hash 函數能夠將這種衝突降到最低。spa

<分離連接>

         解決這種衝突的第一種方法是藉助鏈表來實現,就是將數據實際存放在與 hash 表存儲單元相連接的鏈表中,而不是 hash 的存儲單元中。.net

 

圖 2.1 分離鏈表code

     當產生衝突的時候,將兩個數據都連接在同一 hash 存儲單元保存的鏈表中。當一個存儲單元保存的鏈表中有多個數據的時候,對於鏈表後面的數據的查找添加和刪除就是否是嚴格意義上的 O(1) 了。一個好的 hash 函數可使得這個鏈表很短。最壞狀況下,當全部的數據都保存在一個 hash 單元指定的鏈表中的時候,那麼這個 hash 就和鏈表同樣了。orm

<開放地址>

         使用開放地址方法解決衝突的時候,數據仍然保存在 hash 表的存儲單元中,可是當衝突發生的時候,要再次計算新的地址。blog

         經常使用的開放地址法是線性探查,就是當對一個數據進行插入刪除或者查找的時候,經過 hash 函數計算,發現這個位置不是要找的數據,這時候就檢查下一個存儲單元,一直找到要操做的數據爲止。

         除了線性探查外還有二次探查,再 hash 等等方法,都是當一次計算獲得的位置不是要找到的數據的時候,怎樣再次肯定新的位置。

<徹底 hash 表>

         採用分離鏈表的方式解決衝突的時候,當多個數據被映射到一個地址的時候,它們就造成了一個鏈表,要操做這其中的一個數據,那麼就必須在這個鏈表中進行操做。若是 hash 函數選擇的好的話,鏈表會很短,這樣的操做近似 O(1) ,但並非精確的等於 O(1) ,它與鏈表的長度有關。對於數據的訪問的最壞狀況的訪問也是 O(1) 的 hash 叫作徹底 hash 表。

         這樣的 hash 表是一個兩級的 hash 表,第一級的 hash 與使用分離連接方法的 hash 同樣,可是 hash 存儲單元中指向的不是一個鏈表,而是另外一個 hash 表。

 

圖 4.1 徹底 hash 表

         要當心的選擇一級以及二級的 hash 函數能夠徹底保證在二級 hash 表中不會出現衝突。

經常使用算法

直接定址法 :地址集合 和 關鍵字集合大小相同

數字分析法 :根據須要hash的 關鍵字的特色選擇合適hash算法,儘可能尋找每一個關鍵字的 不一樣點

平方取中法:取關鍵字平方以後的中間極爲做爲哈希地址,一個數平方以後中間幾位數字與數的每一位都相關,取得位數由表長決定。好比:表長爲512,=2^9,能夠取平方以後中間9位二進制數做爲哈希地址。

摺疊法:關鍵字位數不少,並且關鍵字中每一位上的數字分佈大體均勻的時候,能夠採用摺疊法獲得哈希地址,除留取餘法除P取餘,能夠選P爲質數,或者不含有小於20的質因子的合數

隨機數法:一般關鍵字不等的時候採用此法構造哈希函數較恰當。

 

實際工做中須要視不一樣的狀況採用不一樣的hash函數

考慮因素:計算哈希函數所須要的時間,硬件指令等因素。

關鍵字長度

哈希表大小

關鍵字分佈狀況

記錄查找的頻率。(huffeman樹)

具體代碼以下

 
#include<stdlib.h>  
#include<math.h>  
struct HashTable;  
struct ListNote;  
typedef struct HashTable *HashTbl;  
typedef struct ListNote *Position;  
typedef Position List;  
int Hash(int key,int tablesize);  
int NextPrime(int x);  
HashTbl InitalizeTable(int TableSize);  
void DestroyTable(HashTbl H);  
Position Find(int key,HashTbl H);  
void Insert(int key, HashTbl H);  
void Delete(int key,HashTbl H);  
struct HashTable{   
    int TableSize;  
    Position *TheList;  
};  
struct ListNote{  
    int element;  
    Position next;  
};  
int Hash(int key,int tablesize){  
    return key%tablesize;  
}  
int NextPrime(int x){  
    int flag;  
    while(1){  
        flag = 0;  
        int i;  
        int n = sqrt((float)x);  
        for(i = 2 ;i <= n;i++){  
            if(x % i == 0){  
                flag = 1;  
                break;  
            }  
        }  
        if(flag == 0)  
            return x;  
        else  
            x++;  
    }  
}  
HashTbl InitalizeTable(int TableSize){  
    if(TableSize <= 0){  
        printf("散列大小有問題\n");  
        return NULL;  
    }  
    HashTbl table = (HashTbl)malloc(sizeof(struct HashTable));  
    if(table == NULL)  
        printf("分配失敗");  
    table->TableSize = NextPrime(TableSize);  
    table->TheList = (Position*)malloc(sizeof(List) * table->TableSize);  
    if(table->TheList == NULL)  
        printf("分配失敗");  
    table->TheList[0] = (Position)malloc(table->TableSize*sizeof(struct ListNote));  
    if(table->TheList == NULL)  
        printf("分配失敗");  
    int i;  
    for(i = 0;i < table->TableSize;i++){  
        table->TheList[i] = table->TheList[0] + i;  
        table->TheList[i]->next = NULL;  
    }  
    return table;  
}  
Position Find(int key,HashTbl H){  
    Position p;  
    List L = H->TheList[Hash(key,H->TableSize)];  
    p = L->next;  
    while(p != NULL && p->element != key)  
        p = p->next;  
    if(p == NULL)  
        return L;  
    else  
        return p;  
}  
void Insert(int key,HashTbl H){  
    Position p,NewCell;  
    p = Find(key,H);  
    if(p->element != key){  
        NewCell = (Position)malloc(sizeof(struct ListNote));  
        if(NewCell == NULL)  
            printf("分配失敗");  
        else{  
            p = H->TheList[Hash(key,H->TableSize)];  
            NewCell->next = p->next;  
            p->next = NewCell;  
            NewCell->element = key;  
        }  
    }  
    else  
        printf("已經存在該值了\n");  
}  
void Delete(int key,HashTbl H){  
    Position p ,NewCell;  
    p = Find(key,H);  
    if(p->element == key){  
        NewCell = H->TheList[Hash(key,H->TableSize)];  
        while(NewCell->next != p)  
            NewCell = NewCell->next;  
        NewCell->next = p->next;  
        free(p);  
    }  
    else  
        printf("沒有該值");  
}  
int main(){  
    HashTbl table = InitalizeTable(10);  
    Position p = NULL;  
    p = Find(10,table);  
    printf("%d\n",p->element);  
    Insert(55,table);  
    Insert(90,table);  
    Insert(35,table);  
    Insert(33,table);  
    p = Find(55,table);  
    printf("%d\n",p->element);  
    p = Find(33,table);  
    printf("%d\n",p->element);  
    Delete(33,table);  
    Delete(44,table);  
    system( "pause" );  
    return 0 ;  
}  

 

 
 
 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

相關文章
相關標籤/搜索