哈希表的主要作用其實就是處理數據的映射,把數據轉換爲更方便,更容易處理的數據。
而映射就是就是一個函數,稱之爲哈希函數。
通常構造哈希函數需要考慮以下要點:
(1)哈希函數的耗時時間
(2)關鍵字的長度
(3)哈希表的大小
(4)關鍵字的分佈情況
(5)記錄的查找頻率
下面只介紹構造哈希函數最常用的方法也是很簡單的方法:
除留餘數法
取關鍵字被某個不大於哈希表表長m的數p除後所得餘數爲哈希地址。
H(key)=key MOD p (p<=m)
所謂的哈希表表長,就是你計劃定義的數組元素個數的大小。
衝突的處理方法
設置的哈希函數一般可以減少衝突,但避免不了。所以,需要有針對衝突的處理方式。
衝突處理:令數組元素個數爲m ,則當H(key) 已經存儲了元素的時候,依次探查 (H(key)+i) modp , i=1,2,3……,直到找到空的存儲單元爲止(或者從頭到尾掃描一圈仍未發現空單元,這就是哈希表已經滿了,發生了錯誤。當然這是可以通過擴大數組範圍避免的)。
其實意思就是如果H(key)值已經被其他元素佔用了,試下H(key)+1,2,3...
另外一個就是求模時的p儘量使用素數,不選素數的話可能會造成hash出值的範圍和原定義的不一致哈希函數。
舉個例子
好的HASH函數需要把原始數據均勻地分佈到HASH數組裏
原始數據不大會是真正的隨機的,可能有某些規律,
比如大部分是偶數,這時候如果HASH數組容量是偶數,容易使原始數據HASH後不會均勻分佈。
比如 2 4 6 8 10 12這6個數,如果對6
取餘 得到2 4 0 2 4 0
只會得到3種HASH值,衝突會很多
如果對 7 取餘 得到
2 4 6 1 3 5 得到6種HASH值,沒有衝突
同樣地,如果數據都是3的倍數,而HASH數組容量是3的倍數,HASH後也容易有衝突
#ifndef _HASH_H_
#define _HASH_H_
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#define HASH_GENE 4
#define OVER_ (65535*65535)
int hash(char *key_str, unsigned long MAX_SS_NUM);
#endif //_HASH_H_
hash.c
#include "hash.h"
int hash(char *key_str, unsigned long MAX_SS_NUM)
{
register unsigned int h;
register unsigned char *p;
for(h=0, p = (unsigned char *)key_str; *p ; p++)
{
h = 31 * h + *p;
}
return (h % MAX_SS_NUM);
}