暴雪的hash演算法 翻譯

2022-05-22 09:48:12 字數 2630 閱讀 5499

促進歷史進步的大多數契機都是在解決特定問題的過程中產生的,本文討論一下mpq格式的合適解決方案。

----mpq是暴雪的一種文字壓縮格式,可以壓縮包括座標、演算法、聲音、動畫、字串等。

hashs

問題:你可能有乙個非常長的字串陣列,現在有乙個新字串,想要判斷該字串是否在陣列中,簡單粗暴的方法是挨個比較,但最大的弊端就是大部分場合下速度慢到不能忍。

解決方案:hash,hash是一種較小的資料型別,用來替代其他的較大的資料型別(通常是字串),上述的問題可以儲存字串的hash到陣列中,然後比較新字串的hash是否在陣列中,如果陣列中的乙個hash匹配了新字串的hash,該字串就存在於字串陣列中。hash能夠將該比較過程提速約100倍,具體的效率提公升依賴於陣列的長度和字串的平均長度,下面是乙個簡單的hash演算法

unsigned long hashstring(char *lpszstring)

return ulhash;

}

上面的**提供了一種簡單的hash演算法,累加字串的所有字元,在累加字串之前hash的基準值左移一位。這個演算法簡單也很有用,但會生成大量相似的輸出,並且經常是在較小的值域內產生大量衝突,衝突是指兩個不同的字串hash後值一樣。

mpq格式使用了非常複雜的hash演算法來生成全部不可預期的值,事實上該hash演算法是乙個單向演算法,單向演算法是指無法通過hash值反算出原始字串。下面是這個特別的演算法:

unsigned long hashstring(char *lpszfilename, unsigned long dwhashtype)

return seed1;

}

hash表

問題:你使用乙個類似上面例子的索引,但你的程式要求極快的速度,但是索引並沒有足夠快,你唯一能讓索引速度變快的方法是不檢索陣列中的每乙個hash值。更或者你可以只做一次比較就能確定字串是否存在於陣列的任何乙個位置,聽起來爽吧?

解決方案:hash表是一種特殊的陣列,目標字串的偏移量是目標字串的hash值。根據應用程式需要建立指定大小的陣列,(比如說1024,通常是2的n次方),想要確認新字串是否在表裡,為了獲取新字串在hash表的位置,將新字串的hash按照hash表大小進行取模運算,餘數就是新字串在hash表的偏移量。然後將hash表指定偏移位置的字串同新增字串進行比較,如果不存在或者不相等,那麼該字串沒有存在於hash表也即字串陣列中。**如下:

int gethashtablepos(char *lpszstring, somestructure *lptable, int ntablesize)

上面的方法有乙個明顯的問題,如果發生了衝突即兩個不同的字串hash後的值是一樣的,又該怎麼辦?顯然它們不能在hash表占用同樣的位置。乙個常用的解決方式是hash的每乙個節點不再代表乙個元素,而是乙個列表的指標,該列表儲存hash值為該偏移的所有字串。

mpqs使用乙個檔名稱表來跟蹤檔案內部資訊,但這個表和普通的hash表並不完全一樣。首先:不是使用檔名稱的hash值作為偏移量並儲存真實的檔名來做校驗;mpqs根本不會儲存檔名稱,而是使用三個不同的hash值:乙個用來做hash表的偏移位置,兩個用來做校驗,兩個用來校驗的hash代替了真實的檔名稱。這樣還是有可能會出現兩個不同的字串hash到同樣的三個值上,不過這樣的概率非常小,大概是1:18889465931478580854784,誰識數的數一數,我是看不懂了,這樣的概率對每乙個人來說都是足夠安全的。

另外mpqs和通常的hash實現不一樣的地方是:沒有為hash表的每乙個入口儲存乙個鍊錶,在衝突發生的時候繼續向下找,直到找到乙個未被占用的槽。

下面的**描述了mpqs定位乙個用來讀的檔案的過程

int gethashtablepos(char *lpszstring, mpqhashtable *lptable, int ntablesize)

return -1; //error value

}

下面是對**的解釋,大致符合程式查詢並讀取檔案的過程。

1.計算三個hash值並儲存在變數裡。

2.移動到hash偏移量的入口。

3.該入口是否未使用,如果是,停止搜尋,返回查詢失敗。

4.是否入口的兩個檢驗hash等於計算出來的兩個檢驗hash,如果是,停止搜尋並返回該入口。

5.移動到鍊錶的下乙個入口,如果到了末尾就重新從開始查詢。

6.如果查詢的偏移量和計算的hash偏移量是一樣的,已經搜尋了整個表仍然沒有找到,返回未查找到。

7.從第三步重新開始。

如果留心的話,可能會注意到該表是不可擴充套件的,如果所有的入口都被佔據,那就不能夠插入任何的檔名稱,是的,這個表就是這樣設計的,裝載因子最大為1.0.甚至該錶不可以動態擴大,因為擴大會導致所有的hash入口失效,並且不能重新生成該錶,因為不知道相應的檔名稱。

-----如果只是為了乙個傳奇的hash,這裡就應該夠了,hash的原理、hash的應用都有足夠的說明。

壓縮本文的後半部分和主題關係不大,分篇章翻譯,over。

21Hash演算法以及暴雪Hash

一 雜湊表簡介 雜湊表是一種查詢效率極高的資料結構,理想情況下雜湊表插入和查詢操作的時間複雜度均為o 1 任何乙個資料項可以在乙個與雜湊表長度無關的時間內計算出乙個雜湊值 key 然後在常量時間內定位到乙個桶 術語bucket,表示雜湊表中的乙個位置 當然這是理想情況下,因為任何雜湊表的長度都是有限...

暴雪的hash表

具體流程就是建立乙個較大的陣列,然後通過特定的演算法,將字串轉成整數,然後存入到這個陣列中,然後可以通過取模,獲得這個string在陣列中的下標。include include include define maxmpqhashtablelen 8192 typedef struct mpqhash...

暴雪hash演算法,(不理解?稍作改進?)

看了july關於暴雪hash演算法的講解,有幾個地方沒理解。暴雪hash與普通hash不同的是,使用了更好的hash值 使用3個hash值,乙個用於查詢,兩個用於校驗 如果出現衝突,尋找下乙個,如果到了陣列尾部還沒找到,則表示字串不存在。那麼最大的不同應該就是使用三個hash值,在比較的時候不直接比...