引html
在各類數據結構(線性表、樹等)中,記錄在結構中的相對位置是隨機的。所以在機構中查找記錄的時需要進行一系列和keyword的比較。這一類的查找方法創建在「比較」的基礎上。查找的效率依賴於查找過程當中所進行的比較次數。算法
以前咱們介紹的各類基於比較的樹查找算法,這些查找算法的效率都將隨着數據記錄數的增加而降低。數據庫
不過有的比較慢(時間複雜度爲O(n)),有的比較快(時間複雜度是O(logn))而已。這些查找算法的平均查找長度是在一種比較理想的狀況下得到的。數組
在實際應用其中,對數據結構中數據的頻繁添加和刪除將不斷地改變着數據的結構。安全
這些操做將可能致使某些數據結構退化爲鏈表結構,那麼其性能一定將降低。數據結構
爲了不出現這樣的狀況而採取的調整措施。又不可避免的添加了程序的複雜程度以及操做的額外時間。
函數
哈希表 性能
理想的狀況是 但願不通過不論什麼比較,一次存取便能獲得所查的記錄。那就必須在記的存儲位置和它的keyword之間創建一個肯定的相應關係f,使每個keyword和一個惟一的存儲位置相相應。於是在查找時。僅僅要依據這個相應關係f找到給定值K的像f(K)。由此,不需要進行比較即可直接取得所查記錄。在此,咱們稱這個相應關係爲哈希(Hash)函數。按這個思想創建的表爲 哈希表。
哈希樹(HashTree)算法就是要提供一種在理論上和實際應用中均能有效地處理衝突的方法。通常的哈希(Hash)算法都是O(1)的,而且基本是以空間換時間。這很是easy致使對存儲空間無限制的需求。優化
本文中哈希樹(HashTree)算法在實際操做中使用了一些技巧使得對空間的需求控制在必定範圍內。即空間需求僅和所需要存儲的對象個數有關,不會無限制地「膨脹」下去。 spa
哈希樹的理論基礎
「分辨」就是指這些連續的整數不可能有全然一樣的餘數序列。
(這個定理的證實詳見: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次取餘的整數除法操做差點兒不算什麼難事。在實際應用中。整體的操做速度每每取決於節點將keyword裝載內存的次數和時間。通常來講。裝載的時間是由keyword的大小和硬件來決定的;在一樣類型keyword和一樣硬件條件下,實際的整體操做時間就主要取決於裝載的次數。
他們之間是一個成正比的關係。
插入
咱們選擇質數分辨算法來創建一棵哈希樹。
選擇從2開始的連續質數來創建一個十層的哈希樹。第一層結點爲根結點。根結點下有2個結點。第二層的每個結點下有3個結點。依此類推,即每層結點的子節點數目爲連續的質數。
到第十層,每個結點下有29個結點。
同一結點中的子結點。從左到右表明不一樣的餘數結果。
好比:第二層結點下有三個子節點。那麼從左到右分別表明:除3餘0,除3餘1。除3餘2.
對質數進行取餘操做獲得的餘數決定了處理的路徑。
結點結構:結點的keyword(在整個樹中是惟一的),結點的數據對象。結點是否被佔領的標誌位(標誌位爲真時,keyword才被以爲是有效的),和結點的子結點數組。
哈希樹的節點結構
struct Node { keyType key ; ValueType value ; bool occupied ; //用occupied來表示節點是否被佔領。假設節點的keyword(key)有效。那麼occupied應該設置位true,不然設置爲false。(假設在創建當初就創建所有的節點。那麼所消耗的計算時間和磁盤空間是巨大的。struct Node* subNodes[1] ; //咱們用subNodes[i]來表示節點的第i個子節點的地址。(此技術在跳躍表中有介紹,可翻看前面博客) } ;
在實際使用其中,僅僅需要初始化根節點就可以開始工做。
子節點的創建是在有不少其它的數據進入到哈希樹中的時候創建的。所以可以說哈希樹和其它樹同樣是一個動態結構。)
如下咱們以隨機的10個數的插入爲例,來圖解HashTree的插入過程,這個史上最清晰的圖解,你必定能看的明確^_^
有讀者可能有疑問,假設一直衝突下去怎麼辦?首先,若keyword是整型。咱們的10層哈希樹全然可以分辨出來它們,這是質數分辨算法決定的。
(咱們事實上也可以把所有的鍵-值節點放在哈希樹的第10層葉節點處,這第10層的滿節點數就包括了所有的整數個數。但是假設這樣處理的話,所有的非葉子節點做爲鍵-值節點的索引,這樣使樹結構龐大,浪費空間)
【這裏沒有說的太清楚,此圖是以2開始的連續質數建立的,即:從上到下的層級中的每個節點中的子樹個數爲二、三、五、七、十一、1三、1七、1九、2三、29。第一層中的每個節點的子樹個數爲2,第二層中的每個節點子樹個數爲5.。。。。
上圖中的子樹上的數字。是其父節點的子樹指針數組的索引值】
查找
哈希樹的節點查找過程和節點插入過程相似,就是對keyword用質數序列取餘,依據餘數肯定下一節點的分叉路徑,直到找到目標節點。
所以可以依據自身需要在時間和空間上尋求一個平衡點。
刪除
哈希樹的節點刪除過程也很是easy。哈希樹在刪除的時候,並不作不論什麼結構調整。
長處
一、結構簡單
從哈希樹的結構來講。很的簡單。每層節點的子節點個數爲連續的質數。子節點可以隨時建立。所以哈希樹的結構是動態的,也不像某些哈希算法那樣需要長時間的初始化過程。哈希樹也沒有必要爲不存在的keyword提早分配空間。
需要注意的是哈希樹是一個單向添加的結構,即隨着所需要存儲的數據量添加而增大。
即便數據量下降到原來的數量,但是哈希樹的總節點數不會下降。
這樣作的目的是爲了不結構的調整帶來的額外消耗。
二、查找迅速
從算法過程咱們可以看出,對於整數,哈希樹層級最多能添加到10。
所以最多僅僅需要十次取餘和比較操做,就可以知道這個對象是否存在。
這個在算法邏輯上決定了哈希樹的優越性。
通常的樹狀結構。每每隨着層次和層次中節點數的添加而致使不少其它的比較操做。操做次數可以說沒法準確肯定上限。而哈希樹的查找次數和元素個數沒有關係。假設元素的連續keyword總個數在計算機的整數(32bit)所能表達的最大範圍內,那麼比較次數就最多不會超過10次。一般低於這個數值。
三、結構不變
從刪除算法中可以看出,哈希樹在刪除的時候,並不作不論什麼結構調整。這個也是它的一個很好的長處。常規樹結構在添加元素和刪除元素的時候都要作必定的結構調整,不然他們將可能退化爲鏈表結構,而致使查找效率的減小。哈希樹採取的是一種「見縫插針」的算法,歷來不用操心退化的問題,也沒必要爲優化結構而採取額外的操做。所以大大節約了操做時間。
缺點
一、非排序性
哈希樹不支持排序。沒有順序特性。
假設在此基礎上不作不論什麼改進的話並試圖經過遍從來實現排序,那麼操做效率將遠遠低於其它類型的數據結構。
關於超長字符串的問題
【關於MD5】
維基連接:http://zh.wikipedia.org/wiki/MD5
二、easy計算:從原數據計算出MD5值很是easy。
三、抗改動性:對原數據進行不論什麼改動,哪怕僅僅改動1個字節。所獲得的MD5值都有很是大差異。
四、弱抗碰撞:已知原數據和其MD5值,想找到一個具備一樣MD5值的數據(即僞造數據)是很困難的。
五、強抗碰撞:想找到兩個不一樣的數據,使它們具備一樣的MD5值,是很困難的。
(1996年後被證明存在弱點。可以被加以破解,對於需要高度安全性的數據。專家通常建議改用其它算法,如SHA-1)
對於超長字符串,咱們可以用MD5算法生成一個128bit的整數。而後用RadixTree(翻看前面博客)來存儲這個大整數。或者使用哈希樹來存儲,對於這種大整數。咱們不能簡單地使用計算機的整數來作除法,而是使用程序模擬人工的除法方式來作除法並得到餘數。
這樣,使用MD5和選用更大的質數相結合的辦法。這樣就可以使得經過層次比較少的哈希樹來得到對keyword區間的完整覆蓋。這樣就下降了比較操做的次數,並提升整體的工做效率。
應用
哈希樹可以普遍應用於那些需要對大容量數據進行高速匹配操做的地方。
好比:數據庫索引系統、短信息中的收條匹配、大量號碼路由匹配、信息過濾匹配。
哈希樹不需要額外的平衡和防止退化的操做。效率十分理想。
【參考】
http://baike.baidu.com/view/10403049.htm
http://wenku.baidu.com/view/16b2c7abd1f34693daef3e58.html