ELFhash - 优秀的字符串哈希算法
ELFhash - 優秀的字符串哈希算法
?
1.字符串哈希:
我們先從字符串哈希說起 在很多的情況下,我們有可能會獲得大量的字符串,每個字符串有可能重復也有可能不重復 C不像Python有字典類型的數據結構,我們沒有辦法吧字符串當做是鍵值來保存,所以說我們需要一種hash函數將每個字符串都盡可能減少沖突的情況下去應設一個唯一的整形數據,方便我們的保存,這里我們就引入了字符串hash算法現在,有非常多的字符串hash算法都很優秀,本文主要面對ELFhash算法來表述,相對來說比較的清晰
2.ELFhash
首先我需要聲明,字符串hash算法ELFhash的算法的形成的三列的均勻性我不會證明 根據其他的大牛的描述,ELFhash算法對于長字符串和短字符串都有優良的效率,以下的數據援引劉愛貴大神的實驗數據:Hash應用中,字符串是最為常見的關鍵字,應用非常普通,現在的程序設計語言中基本上都提供了字符串hash表的支持。字符串hash函數非常多,常見的主要有Simple_hash, RS_hash, JS_hash, PJW_hash, ELF_hash, BKDR_hash, SDBM_hash, DJB_hash, AP_hash, CRC_hash等。它們的C語言實現見后面附錄代碼: hash.h, hash.c。那么這么些字符串hash函數,誰好熟非呢?評估hash函數優劣的基準主要有以下兩個指標:
(1)?散列分布性
即桶的使用率backet_usage = (已使用桶數) / (總的桶數),這個比例越高,說明分布性良好,是好的hash設計。
(2) 平均桶長
即avg_backet_len,所有已使用桶的平均長度。理想狀態下這個值應該=1,越小說明沖突發生地越少,是好的hash設計。
hash函數計算一般都非常簡潔,因此在耗費計算時間復雜性方面判別甚微,這里不作對比。
?
評估方案設計是這樣的:
(1) 以200M的視頻文件作為輸入源,以4KB的塊為大小計算MD5值,并以此作為hash關鍵字;
(2) 分別應用上面提到的各種字符串hash函數,進行hash散列模擬;
(3) 統計結果,用散列分布性和平均桶長兩個指標進行評估分析。
?
測試程序見附錄代碼hashtest.c,測試結果如下表所示。從這個結果我們也可以看出,這些字符串hash函數真是不相仲伯,難以決出高低,所以實際應用中可以根據喜好選擇。當然,最好實際測試一下,畢竟應用特點不大相同。其他幾組測試結果也類似,這里不再給出。
| Hash函數 | 桶數 | Hash調用總數 | 最大桶長 | 平均桶長 | 桶使用率% |
| simple_hash | 10240 | 47198 | 16 | 4.63 | 99.00% |
| RS_hash | 10240 | 47198 | 16 | 4.63 | 98.91% |
| JS_hash | 10240 | 47198 | 15 | 4.64 | 98.87% |
| PJW_hash | 10240 | 47198 | 16 | 4.63 | 99.00% |
| ELF_hash | 10240 | 47198 | 16 | 4.63 | 99.00% |
| BKDR_hash | 10240 | 47198 | 16 | 4.63 | 99.00% |
| SDBM_hash | 10240 | 47198 | 16 | 4.63 | 98.90% |
| DJB_hash | 10240 | 47198 | 15 | 4.64 | 98.85% |
| AP_hash | 10240 | 47198 | 16 | 4.63 | 98.96% |
| CRC_hash | 10240 | 47198 | 16 | 4.64 | 98.77% |
3.原理:
首先,我們在開始之前需要明確幾點 1.unsigned int有4個字節,32個比特位 2.異或操作中0是單位元,任何數與1異或相當于取反 3.unsigned無符號類型的數據右移操作均是執行邏輯右移(左高位自動補0) 4.ELFhash算法的核心在于“影響“先附上代碼: [cpp]?view plain?copy ?
- unsigned?int?ELFhash(char?*str)??
- {??
- ????unsigned?int?hash=0;??
- ????unsigned?int?x=0;??
- ????while(*str)??
- ????{??
- ????????hash=(hash<<4)+*str;?????//1??
- ????????if((x=hash?&?0xf0000000)!=0)?????????//2??
- ????????{??
- ????????????hash^=(x>>24);???//影響5-8位,雜糅一次???3??
- ????????????hash&=~x;???//清空高四位????4??
- ????????}??
- ????????str++;???//5??
- ????}??
- ????return?(hash?&?0x7fffffff);????//6???
- }??
解釋: 首先我們的hash結果是一個unsigned int類型的數據: 0000 0000 0000 0000 1.hash左移4位,將str插入(一個char有八位)這里我開始也一直是懷疑的態度,那么第一個字節的高四位不就亂了嗎 實際上這也是我們的第一次雜糅,我們是故意這么做的,這里我們需要注意標記一下,我們在第一個字節的高四位做了第一次雜糅 2.x這里用0xf0000000獲取了hash的第四個字節的高四位,并用高四位作為掩碼做第二次雜糅 在這里我們首先聲明一下,因為我們的ELFhash強調的是每個字符都要對最后的結構有影響,所以說我們左移到一定程度是會吞掉最高的四位的,所以說我們要將最高的四位先對串產生影響,再讓他被吞掉,之后的所有的影響都是疊加的,這就是多次的雜糅保證散列均勻,防止出現沖突的大量出現 3.x掩碼右移24位移動到剛才的5-8位哪里在對5-8位進行第二次雜糅 4.我們定時清空高四位,實際上這部操作我們完全沒有必要,但是算法要求,因為我們下一次的左移會自動吞掉這四位//這里存疑,不會減少我們的hash的范圍? 5.str遞增,引入下一個字符進行雜糅 6.返回一個缺失了最高符號位的無符號數(為了之后防止用到了有符號的時候造成的溢出)作為最后的hash值
4.Code:
[cpp]?view plain?copy ?- /*#include"iostream"?
- #include"cstdio"?
- #include"cstring"?
- ?
- using?namespace?std;?
- ?
- unsigned?int?a=0x80;?
- ?
- int?main()?
- {?
- ????printf("%d\n",a>>1);???//無符號數實行邏輯右移??
- ????return?0;?
- }?*/??
- ??
- #include"iostream"??
- #include"cstdio"??
- #include"cstring"??
- ??
- using?namespace?std;??
- ??
- unsigned?int?ELFhash(char?*str)??
- {??
- ????unsigned?int?hash=0;??
- ????unsigned?int?x=0;??
- ????while(*str)??
- ????{??
- ????????hash=(hash<<4)+*str;??
- ????????if((x=hash?&?0xf0000000)!=0)??
- ????????{??
- ????????????hash^=(x>>24);???//影響5-8位,雜糅一次???
- ????????????hash&=~x;???//清空高四位???
- ????????}??
- ????????str++;??
- ????}??
- ????return?(hash?&?0x7fffffff);???
- }??
- ??
- int?main()??
- {??
- ????char?data[100];??
- ????memset(data,0,sizeof(data));??
- ????scanf("%s",data);??
- ????printf("%d\n",ELFhash(data));??
- ????return?0;??
- }???
最后,按照我的思路來看的話,ELFhash最多可以散列的空間的大小是幾個億的數據?如果去掉hash&=~x這一句的話會不會擴大我們hash的范圍,盡可能利用空間,我下星期問問數據結構老師好了!
5.應用:
我們在對內存地址的進行的操作的時候,可以將數據的內存地址進行哈希 因為每個數據的內存地址都是唯一的,所以我們只需要一步獲取內存地址的十六進制的表示就可以了 語句是 [cpp]?view plain?copy ?- sprintf(data,"%0x",&now_data);??
利用這種思路,我們可以很清晰明了的對鏈表相交的問題構建一種新的解法,我們采用哈希我們的內存空間就可以了,可以再O(n)中完成查找
總結
以上是生活随笔為你收集整理的ELFhash - 优秀的字符串哈希算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上海欢乐谷残疾人优惠政策
- 下一篇: 字符串匹配shiftand算法