? Hash,一般翻譯做“散列”,就是把任意長度的輸入(又叫做預(yù)映射,pre-image),通過散列算法,變換成固定長度的輸出,該輸出就是散列值。這種轉(zhuǎn)換是一種壓縮映射,也就是,散列值的空間通常遠(yuǎn)小于輸入的空間,不同的輸入可能會散列成相同的輸出,而不可能從散列值來唯一的確定輸入值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數(shù)。
?散列函數(shù)能使對一個數(shù)據(jù)序列的訪問過程更加迅速有效,通過散列函數(shù),數(shù)據(jù)元素將被更快地定位。常用Hash函數(shù)有:
?1.直接尋址法。取關(guān)鍵字或關(guān)鍵字的某個線性函數(shù)值為散列地址。即H(key)=key或H(key)=a·key+b,其中a和b為常數(shù)(這種散列函數(shù)叫做自身函數(shù))
?2.?dāng)?shù)字分析法。分析一組數(shù)據(jù),比如一組員工的出生年月日,這時我們發(fā)現(xiàn)出生年月日的前幾位數(shù)字大體相同,這樣的話,出現(xiàn)沖突的幾率就會很大,但是我們發(fā)現(xiàn)年月日的后幾位表示月份和具體日期的數(shù)字差別很大,如果用后面的數(shù)字來構(gòu)成散列地址,則沖突的幾率會明顯降低。因此數(shù)字分析法就是找出數(shù)字的規(guī)律,盡可能利用這些數(shù)據(jù)來構(gòu)造沖突幾率較低的散列地址。
?3.平方取中法。取關(guān)鍵字平方后的中間幾位作為散列地址。
?4.折疊法。將關(guān)鍵字分割成位數(shù)相同的幾部分,最后一部分位數(shù)可以不同,然后取這幾部分的疊加和(去除進(jìn)位)作為散列地址。
?5.隨機(jī)數(shù)法。選擇一隨機(jī)函數(shù),取關(guān)鍵字作為隨機(jī)函數(shù)的種子生成隨機(jī)值作為散列地址,通常用于關(guān)鍵字長度不同的場合。
?6.除留余數(shù)法。取關(guān)鍵字被某個不大于散列表表長m的數(shù)p除后所得的余數(shù)為散列地址。即H(key)=key MOD p,p<=m。不僅可以對關(guān)鍵字直接取模,也可在折疊、平方取中等運(yùn)算之后取模。對p的選擇很重要,一般取素數(shù)或m,若p選的不好,容易產(chǎn)生碰撞。
?public class ConsistentHashingWithoutVirtualNode{
?//待添加入Hash環(huán)的服務(wù)器列表
?private static String[]servers={"192.168.0.1:8888","192.168.0.2:8888",
?"192.168.0.3:8888"};
?//key表示服務(wù)器的hash值,value表示服務(wù)器
?private static SortedMapsortedMap=new TreeMap();,string>,string>
?//程序初始化,將所有的服務(wù)器放入sortedMap中
?static{
?for(int i=0;i;i++){<>
?int hash=getHash(servers);
?System.out.println("["+servers+"]加入集合中,其Hash值為"+hash);
?sortedMap.put(hash,servers);
?}
?}
?//得到應(yīng)當(dāng)路由到的結(jié)點
?private static String getServer(String key){
?//得到該key的hash值
?int hash=getHash(key);
?//得到大于該Hash值的所有Map
?SortedMapsubMap=sortedMap.tailMap(hash);,string>
?if(subMap.isEmpty()){
?//如果沒有比該key的hash值大的,則從第一個node開始
?Integer i=sortedMap.firstKey();
?//返回對應(yīng)的服務(wù)器
?return sortedMap.get(i);
?}else{
?//第一個Key就是順時針過去離node最近的那個結(jié)點
?Integer i=subMap.firstKey();
?//返回對應(yīng)的服務(wù)器
?return subMap.get(i);
?}
?}
?//使用FNV1_32_HASH算法計算服務(wù)器的Hash值
?private static int getHash(String str){
?final int p=16777619;
?int hash=(int)2166136261L;
?for(int i=0;i();i++)<>
?hash=(hash^str.charAt(i))*p;
?hash+=hash<<13;
?hash^=hash>>7;
?hash+=hash<<3;
?hash^=hash>>17;
?hash+=hash<<5;
?//如果算出來的值為負(fù)數(shù)則取其絕對值
?if(hash<0)
?hash=Math.abs(hash);
?return hash;
?}
?public static void main(String[]args){
?String[]keys={"semlinker","kakuqo","fer"};
?for(int i=0;i;i++)<>
?System.out.println("["+keys+"]的hash值為"+getHash(keys)
?+",被路由到結(jié)點["+getServer(keys)+"]");
?}
?}
審核編輯:符乾江
電子發(fā)燒友App



































評論