1. 程式人生 > >查詢——圖文詳解HashTree(雜湊樹)

查詢——圖文詳解HashTree(雜湊樹)

在各種資料結構(線性表、樹等)中,記錄在結構中的相對位置是隨機的。因此在機構中查詢記錄的時需要進行一系列和關鍵字的比較。這一類的查詢方法建立在“比較”的基礎上。查詢的效率依賴於查詢過程中所進行的比較次數

之前我們介紹的各種基於比較的樹查詢演算法,這些查詢演算法的效率都將隨著資料記錄數的增長而下降。僅僅是有的比較慢(時間複雜度為O(n)),有的比較快(時間複雜度是O(logn))而已。這些查詢演算法的平均查詢長度是在一種比較理想的情況下獲得的。在實際應用當中,對資料結構中資料的頻繁增加和刪除將不斷地改變著資料的結構。這些操作將可能導致某些資料結構退化為連結串列結構,那麼其效能必然將下降。為了避免出現這種情況而採取的調整措施,又不可避免的增加了程式的複雜程度以及操作的額外時間。

雜湊表

理想的情況是希望不經過任何比較,一次存取便能得到所查的記錄,那就必須在記的儲存位置和它的關鍵字之間建立一個確定的對應關係f,使每個關鍵字和一個唯一的儲存位置相對應。因而在查詢時,只要根據這個對應關係f找到給定值K的像f(K)。由此,不需要進行比較便可直接取得所查記錄。在此,我們稱這個對應關係為雜湊(Hash)函式,按這個思想建立的表為雜湊表

在雜湊表中對於不同的關鍵字可能得到同一雜湊地址,這種現象稱做衝突。在一般情況下,衝突只能儘可能地減少,而不能完全避免。因為雜湊函式是從關鍵字集合到地址集合的映像。通常關鍵字的集合比較大,它的元素包括所有可能的關鍵字,而地址集合的元素僅為雜湊表中的地址值。在一般情況下,雜湊函式是一個壓縮映像函式
,這就不可避免的要產生衝突。


雜湊樹(HashTree)演算法就是要提供一種在理論上和實際應用中均能有效地處理衝突的方法。一般的雜湊(Hash)演算法都是O(1)的,而且基本是以空間換時間。這很容易導致對儲存空間無限制的需求。本文中雜湊樹(HashTree)演算法在實際操作中使用了一些技巧使得對空間的需求控制在一定範圍內。即空間需求僅和所需要儲存的物件個數有關,不會無限制地“膨脹”下去。

雜湊樹的理論基礎

質數分辨定理
簡單地說就是:n個不同的質數可以“分辨”的連續整數的個數和他們的乘積相等。“分辨”就是指這些連續的整數不可能有完全相同的餘數序列。
(這個定理的證明詳見:http://wenku.baidu.com/view/16b2c7abd1f34693daef3e58.html


例如:
從2起的連續質數,連續10個質數就可以分辨大約M(10) =2*3*5*7*11*13*17*19*23*29= 6464693230 個數,已經超過計算機中常用整數(32bit)的表達範圍。連續100個質數就可以分辨大約M(100) = 4.711930 乘以10的219次方。
而按照目前的CPU水平,100次取餘的整數除法操作幾乎不算什麼難事。在實際應用中,整體的操作速度往往取決於節點將關鍵字裝載記憶體的次數和時間。一般來說,裝載的時間是由關鍵字的大小和硬體來決定的;在相同型別關鍵字和相同硬體條件下,實際的整體操作時間就主要取決於裝載的次數。他們之間是一個成正比的關係。

插入

我們選擇質數分辨演算法來建立一棵雜湊樹。
選擇從2開始的連續質數來建立一個十層的雜湊樹。第一層結點為根結點,根結點下有2個結點;第二層的每個結點下有3個結點;依此類推,即每層結點的子節點數目為連續的質數。到第十層,每個結點下有29個結點。
同一結點中的子結點,從左到右代表不同的餘數結果。
例如:第二層結點下有三個子節點。那麼從左到右分別代表:除3餘0,除3餘1,除3餘2.
對質數進行取餘操作得到的餘數決定了處理的路徑

結點結構:結點的關鍵字(在整個樹中是唯一的),結點的資料物件,結點是否被佔據的標誌位(標誌位為真時,關鍵字才被認為是有效的),和結點的子結點陣列。
雜湊樹的節點結構

[cpp] view plaincopyprint?
  1. struct Node  
  2. {  
  3.     keyType      key ;  
  4.     ValueType    value ;  
  5.     bool         occupied ;    //用occupied來表示節點是否被佔據。如果節點的關鍵字(key)有效,那麼occupied應該設定位true,否則設定為false。
  6.     struct Node* subNodes[1] ; //我們用subNodes[i]來表示節點的第i個子節點的地址。(此技術在跳躍表中有介紹,可翻看前面部落格)
  7. } ;  
(如果在建立當初就建立所有的節點,那麼所消耗的計算時間和磁碟空間是巨大的。在實際使用當中,只需要初始化根節點就可以開始工作。子節點的建立是在有更多的資料進入到雜湊樹中的時候建立的。因此可以說雜湊樹和其他樹一樣是一個動態結構。)


下面我們以隨機的10個數的插入為例,來圖解HashTree的插入過程,這個史上最清晰的圖解,你一定能看的明白^_^

有讀者可能有疑問,如果一直衝突下去怎麼辦?首先,若關鍵字是整型,我們的10層雜湊樹完全可以分辨出來它們,這是質數分辨演算法決定的。

(我們其實也可以把所有的鍵-值節點放在雜湊樹的第10層葉節點處,這第10層的滿節點數就包含了所有的整數個數,但是如果這樣處理的話,所有的非葉子節點作為鍵-值節點的索引,這樣使樹結構龐大,浪費空間)

【這裡沒有說的太清楚,此圖是以2開始的連續質數建立的,即:從上到下的層級中的每個節點中的子樹個數為2、3、5、7、11、13、17、19、23、29。第一層中的每個節點的子樹個數為2,第二層中的每個節點子樹個數為5.。。。。

上圖中的子樹上的數字,是其父節點的子樹指標陣列的索引值】

查詢

雜湊樹的節點查詢過程和節點插入過程類似,就是對關鍵字用質數序列取餘,根據餘數確定下一節點的分叉路徑,直到找到目標節點
如上圖,最小”雜湊樹(HashTree)在從4G個物件中找出所匹配的物件,比較次數不超過10次。也就是說:最多屬於O(10)。在實際應用中,調整了質數的範圍,使得比較次數一般不超過5次。也就是說:最多屬於O(5)。因此可以根據自身需要在時間和空間上尋求一個平衡點。

刪除

雜湊樹的節點刪除過程也很簡單,雜湊樹在刪除的時候,並不做任何結構調整。
只是先查到到要刪除的節點,然後把此節點的“佔位標記”置為false即可(即表示此節點為空節點,但並不進行物理刪除)。

優點

1、結構簡單

從雜湊樹的結構來說,非常的簡單。每層節點的子節點個數為連續的質數。子節點可以隨時建立。因此雜湊樹的結構是動態的,也不像某些雜湊演算法那樣需要長時間的初始化過程。雜湊樹也沒有必要為不存在的關鍵字提前分配空間。
需要注意的是雜湊樹是一個單向增加的結構,即隨著所需要儲存的資料量增加而增大。即使資料量減少到原來的數量,但是雜湊樹的總節點數不會減少。這樣做的目的是為了避免結構的調整帶來的額外消耗。

2、查詢迅速

從演算法過程我們可以看出,對於整數,雜湊樹層級最多能增加到10。因此最多隻需要十次取餘和比較操作,就可以知道這個物件是否存在。這個在演算法邏輯上決定了雜湊樹的優越性。
一般的樹狀結構,往往隨著層次和層次中節點數的增加而導致更多的比較操作。操作次數可以說無法準確確定上限。而雜湊樹的查詢次數和元素個數沒有關係。如果元素的連續關鍵字總個數在計算機的整數(32bit)所能表達的最大範圍內,那麼比較次數就最多不會超過10次,通常低於這個數值。 

3、結構不變

從刪除演算法中可以看出,雜湊樹在刪除的時候,並不做任何結構調整。這個也是它的一個非常好的優點。常規樹結構在增加元素和刪除元素的時候都要做一定的結構調整,否則他們將可能退化為連結串列結構,而導致查詢效率的降低。雜湊樹採取的是一種“見縫插針”的演算法,從來不用擔心退化的問題,也不必為優化結構而採取額外的操作,因此大大節約了操作時間。


缺點

1、非排序性

雜湊樹不支援排序,沒有順序特性。如果在此基礎上不做任何改進的話並試圖通過遍歷來實現排序,那麼操作效率將遠遠低於其他型別的資料結構。

關於超長字串的問題

如果是超長字串的關鍵字,該如何處理?若把它們按26進位制每一位都轉換為數字,則得到的結果太大。
我們可以用MD5等訊息壓縮演算法來生成定長的整數。

關於MD5

維基連結:http://zh.wikipedia.org/wiki/MD5
MD5(Message Digest Algorithm 訊息摘要演算法第五版)
一種被廣泛使用的密碼雜湊函式,可以產生出一個128位(16位元組)的雜湊值(hash value),用於確保資訊傳輸完整一致。

MD5演算法具有以下特點:
1、壓縮性:任意長度的資料,算出的MD5值長度都是固定的
2、容易計算:從原資料計算出MD5值很容易。
3、抗修改性:對原資料進行任何改動,哪怕只修改1個位元組,所得到的MD5值都有很大區別。
4、弱抗碰撞:已知原資料和其MD5值,想找到一個具有相同MD5值的資料(即偽造資料)是非常困難的。
5、強抗碰撞:想找到兩個不同的資料,使它們具有相同的MD5值,是非常困難的。
(1996年後被證實存在弱點,可以被加以破解,對於需要高度安全性的資料,專家一般建議改用其他演算法,如SHA-1)

對於超長字串,我們可以用MD5演算法生成一個128bit的整數,然後用RadixTree(翻看前面部落格)來儲存這個大整數,或者使用雜湊樹來儲存,對於這樣的大整數,我們不能簡單地使用計算機的整數來做除法,而是使用程式模擬人工的除法方式來做除法並獲得餘數。
這樣,使用MD5和選用更大的質數相結合的辦法。這樣就可以使得通過層次比較少的雜湊樹來獲得對關鍵字區間的完整覆蓋。這樣就減少了比較操作的次數,並提高整體的工作效率。

應用

雜湊樹可以廣泛應用於那些需要對大容量資料進行快速匹配操作的地方。例如:資料庫索引系統、簡訊息中的收條匹配、大量號碼路由匹配、資訊過濾匹配。雜湊樹不需要額外的平衡和防止退化的操作,效率十分理想。

【參考】

http://baike.baidu.com/view/10403049.htm
http://wenku.baidu.com/view/16b2c7abd1f34693daef3e58.html

----------------------------------