Hash函式及其應用

tuoxieyz發表於2015-06-12

本文部分內容摘自網路,參考資料連結會在文後給出,在此感謝原作者的分享。

計算理論中,沒有Hash函式的說法,只有單向函式的說法。所謂的單向函式,是一個複雜的定義,大家可以去看計算理論或者密碼學方面的資料。用“人類”的語言描述,單向函式就是:如果某個函式在給定輸入的時候,很容易計算出其結果來;而當給定結果的時候,很難計算出輸入來,這就是單向函式。各種加密函式都可以被認為是單向函式的逼近。Hash函式(或者稱為雜湊函式)也可以看成是單向函式的一個逼近。即它接近於滿足單向函式的定義。 

Hash函式還有另外的含義。實際中的Hash函式是指把一個大範圍對映到一個小範圍。把大範圍對映到一個小範圍的目的往往是為了節省空間,使得資料容易儲存。除此以外,Hash函式往往應用於查詢上。所以,在考慮使用Hash函式之前,需要明白它的幾個限制:

  • Hash的主要原理就是把大範圍對映到小範圍;所以,你輸入的實際值的個數必須和小範圍相當或者比它更小。不然衝突就會很多。
  • 由於Hash逼近單向函式;所以,你可以用它來對資料進行加密。
  • 不同的應用對Hash函式有著不同的要求;比如,用於加密的Hash函式主要考慮它和單項函式的差距,而用於查詢的Hash函式主要考慮它對映到小範圍的衝突率。

由於實現了Hash的資料結構支援隨機讀取(即直接定位,而不需要涉及各類查詢演算法),檢索效率非常高,成為了很多儲存引擎的首選,著名的有redis、memcache等,但是Hash的特性決定了一些應用場景下的不足:

  • Hash 索引僅僅能滿足”=”,”IN”和”<=>”查詢,不能使用範圍查詢。
  • Hash 索引無法被用來避免資料的排序操作。(即Hash函式並不會自排序,相對的如B樹,本身帶有排序資訊,在節點增刪改時按規則維護)
  • Hash 索引不能利用部分索引鍵查詢。

稍加擴充套件的話,我們還可以將Hash應用在各種資料分散式技術中,這方面說的比較多的是“一致性雜湊演算法”,著名的開源分散式NoSQL資料庫系統Cassandra就應用了這一演算法。

對於資料檢索的低層面應用,主要是各類集合型別。在設計相關型別時,要考慮適當的Hash演算法,考慮因素主要是以下幾個方面:

  • 計算Hash值所需的時間。
  • Hash表長度。
  • Hash值分佈情況。
  • 資料的查詢頻率。
  • Hash值衝突(重複)的概率。

衝突解決技術可分為兩大類:開雜湊法(又稱為鏈地址法)和閉雜湊法(又稱為開發地址法)。可假設實現Hash結構時,資料存放在預先用陣列實現的一片連續的地址空間,兩種衝突解決技術的區別在於發生衝突的元素是儲存在這片陣列的空間之外(開雜湊法,一般為附加連結串列形式)還是空間之內(閉雜湊法)。與閉雜湊法相比,開雜湊法有如下優缺點:

  • 開雜湊法處理衝突無二次聚集現象,因此平均查詢時間較短。
  • 由於開雜湊法中各連結串列上的節點空間是動態申請的,因此適合無法確定表長的情況。
  • 指標需要額外空間,故當記錄規模較小時,閉雜湊法較為節省空間。
  • 在.NET中,連結串列的各個元素分散於託管堆各處,這會給垃圾回收帶來壓力,影響程式效能。

在C#中,實現了Hash函式的集合類我知道的有兩個:System.Collections.Hashtable和System.Collections.Generic.Dictionary<TKey,TValue>,這兩者區別如下:

  • Hashtable採用閉雜湊法來解決衝突,而Dictionary採用開雜湊法來解決衝突。
  • Hashtable在空間不夠時,會自動擴容,在擴容時會重新計算所有元素的雜湊碼和雜湊地址,會消耗大量時間進行計算,Dictionary不存在這個問題(自然Dictionary在空間不夠時也要開闢新的空間,不過不需要重新計算和安排原有資料的雜湊值和雜湊地址,這方面內容可看Dictionary的原始碼便一清二楚了。
  • Hashtable的執行緒安全包含幾個層次,預設可由多個讀取器執行緒一個寫入執行緒使用;若要允許多執行緒寫入(在沒有執行緒讀取的情況下),則需要通過Synchronized方法返回的包裝完成;如果使用一個或多個讀取器以及一個或多個編寫器,則Synchronized包裝不提供執行緒安全的訪問,此時應使用SyncRoot鎖定集合。(MSDN說了這麼多,然後告訴我說Hashtable是執行緒安全的,難道不是在玩我?)Dictionary沒這麼複雜,只要Lock(SyncRoot)即可。

ps:關於NoSql,文中涉及了若干NoSql資料庫,博主就在此簡單說下對NoSql的一些個人見解。現在NoSql可謂風生水起,恰如當年web2.0、ajax剛興起的時候,其實都不是非常高深的技術,但卻能打破傳統,一領風騷好多年,所以說技術是其次,思想才是最重要的。ok扯遠了,NoSql和Sql儲存引擎差不多,總歸就那麼幾種,文中說到的Hash是一種,B數是一種,還有LSM樹之類的,頂多在區域性稍作改進以適應場景。它們真正的區別在於,NoSql不必非常顧忌資料庫正規化的約束,從而極大提高了讀寫速度和擴充套件能力,比如寫操作不care事務,在每秒寫幾萬幾十萬的資料量下,光這點就能甩Sql幾條街。可以說各類NoSql的爭奇鬥豔,其實都是以取消或部分取消資料庫正規化的約束為前提,看似很小的改變,能換來效能的巨大提升,當然這也伴隨著資料冗餘、安全性不高等Sqls深惡痛絕的問題。上帝總是公平的,任何事物都沒有絕對的好壞,就看你把它們用在什麼地方。

參考資料:

Hash函式的幾種

一致性雜湊演算法應用及優化(最簡潔明瞭的教程)

三種基本的儲存引擎比較

NoSQL資料庫探討之一 - 為什麼要用非關聯式資料庫?

 

轉載請註明本文出處:http://www.cnblogs.com/newton/p/4561273.html


相關文章