先說明一下,她們兩個屬於不同的範疇,雙雜湊屬於開放定址法,仍是一種解決衝突的策略。而再雜湊是為了解決插入操作執行時間過長、插入失敗問題的策略。簡而言之,她們的區別在於:前者讓雜湊表做的「對」(把衝突元素按規則安排到合理位置),後者讓雜湊表具有了可擴充性,可以動態調整(不用擔心填滿了怎麼辦)。
我們來考察最後乙個衝突解決方法,雙雜湊(double hashing)。常用的方法是讓f(i)= i * hash2( x ),這意思是用第二個雜湊函式算出x的雜湊值,然後在距離hash2( x ),2hash2( x )的地方探測。hash2( x )作為關鍵,必須要合理選取,否則會引起災難性的後果——各種撞車。這個策略暫時不做過多分析了。
之前說過,對於使用平方探測法的閉雜湊裡,如果元素填的太滿的話後續插入將耗費過長的時間,甚至可能insert失敗,因為這裡面會有太多的移動和插入混合操作。怎麼辦呢?一種解決方法是建立另外乙個大約兩倍大的表,再用乙個新的雜湊函式,掃瞄整個原始表然後按照新的對映插入到新的表裡。
再雜湊的目的是為了後續的插入方便。
比如我們把插入到size=7的閉雜湊裡,hash(x)= x % 7,用線性探測的方法解決衝突,會得到這樣乙個結果:
現在還剩23,把這個插入之後,整個表裡就填滿了70%以上:
於是我們要建立乙個新的表,newsize=17,這是離原規模2倍大小的最近素數。新的雜湊函式是hash( x ) = x % 17。掃瞄原來的表,把所有元素插入到新的表裡,得到這個:
這一頓操作就是再雜湊。可以看出這會付出很昂貴的代價:執行時間o(n
)o(n)
o(n)
,不過慶幸的是實際情況裡並不會經常需要我們再雜湊,都是等快填滿了才做一次,所以還沒那麼差。得說明一下,這種技術是對程式設計師友好而對使用者不友好的。因為如果我們把這種結構應用於某個程式,那並不會有什麼顯著的效果,另一方面,如果再雜湊作為互動系統的一部分執行,可能使使用者感到系統變慢。所以到底用不用還是要權衡一番的,執行速度不敏感的場景就可以用,方便自己,因為這個技術把程式設計師從對錶規模的擔心中解放出來了。
具體實現可以用平方探測以很多種方式實現:
只要表有一半滿了就做
只有當插入失敗時才做(這種比較極端)
途中策略:當表到達某個裝填因子時再做。
由於隨著裝填因子的增加,表的效能會有所下降,所以第三個方法或許是最好的。再雜湊把程式設計師從對錶規模的擔心中解放出來了,這一點的重要之處在於在複雜程式中雜湊表不可能一開始就做得很大,然後高枕無憂。因為我們也不知道多大才夠用,所以能使她動態調整這個特性就很有必要了。實現的時候也比較簡單
hashtable rehash
(hashtable h)
}free
(oldcells)
;return h;
}
雜湊篇的開頭就說了,這不是一種單純的技術,而是一種思想。所以我們不必機械地理解她,可以把這種思想靈活地用在其他結構中,比如在佇列變滿的時候,可以宣告乙個雙倍大小的陣列,然後拷貝過來,釋放原來的佇列。這就有點像向量的規模調整了,聯絡的普遍性再一次得到印證。雜湊篇到這裡就要結束了,在收尾之際我們不妨做乙個總結,回眸下這一路沿途的風景。
雜湊表可以用o(1)o(1)
o(1)
的平均時間完成insert和find,在使用雜湊的時候要尤其注意裝填因子的問題,因為他是保證時間上確界的關鍵。對於分離鏈結法,盡量讓λ接近1。對於開放定址法來說,不到萬不得已就別讓λ太大,盡量保持λ<=0.5。如果用線性探測,效能會隨著λ趨向於1而急劇下降。再雜湊運算可以通過表的伸縮來完成,這樣就會保持λ處於合理範圍,而且優點還在於,如果當下空間緊缺的話,這麼做是很棒的策略。
比較一下二叉查詢樹和雜湊,二叉查詢樹也可以實現insert和find,效率會比雜湊低一些,o(logn)。雖說這方面慢了一點,但是二叉樹能支援更多的操作,比如可以findmin和findmax,這個雜湊就做不到了。還有,二叉查詢樹可以迅速找到在一定範圍內的所有元素,雜湊也做不到,而且o(logn )也不會比o(1)慢太多,因為查詢樹不需要做乘除法,就彌補了一些速度缺陷,綜上看來她們也算是各有千秋。
說完了平均時間,再說說最壞情況雜湊的最壞情況一般是實現的缺憾,而二叉樹的最壞情況呢,是輸入序列有序的時候,那這個時候根據bst規則,二叉樹會退化成一條單鏈,公升序的輸入會導致一捺的情形,降序輸入會形成一撇。這要是再增刪查改付出的可就是o(n)了。平衡查詢樹的實現相對複雜一些,所以如果不需要有序的資訊以及對輸入是否排序有要求的話,就該選擇雜湊這種結構。
雜湊還有著豐富的應用,這裡舉四個例子:第乙個,編譯器使用雜湊表跟蹤源代中宣告的變數,這種資料結構叫做符號表。雜湊表示這種問題的理想應用,因為只有insert和find操作。而且識別符號一般都很短,所以根據這個短字串能迅速算出雜湊值。第二個,在圖論的應用,對於節點有實際名字而不是數字的圖論問題都可以用雜湊表來做。比如某個頂點叫計算機,那麼某個特定的超算中心對應的計算機列表裡有ibm1,ibm2,ibm3這樣的。如果用查詢樹來做這個事,那效率就很滑稽了2333 第三種用途是在為遊戲編制的程式裡。程式搜尋遊戲不同的行(row,不是同行那個行)時,根據實時位置計算出乙個雜湊值,然後跟蹤這些值來確定位置。如果同樣的位置再出現,那麼程式會用簡單的移動變換來避免重複計算,因為重複計算的代價都很大。遊戲程式的這種叫做變換表。
總而言之,揚長避短地選用不同結構處理工作才是我們學習資料結構的第一要義。關於再雜湊和雙雜湊之前一直混淆,現在理一下:
對於雙雜湊其實是在解決雜湊衝突時的一種探測的方法,其用到兩個雜湊函式,這是開放定址法(處理衝突的方法,區別於開雜湊(拉鍊法,也是處理衝突的,只不過前面那個是順序儲存(閉雜湊),而開雜湊是鏈式儲存))的一種策略,王道書中也稱這種方法叫做再雜湊法(這正是自己混淆的所在)。
而再雜湊是一種處理插入時,處理時間長,甚至是插入失敗的問題(雜湊表太滿了),這時我們要讓它換到乙個2倍的空間裡去,於是用以前的雜湊函式去把表中的元素找到,再用新的雜湊函式處理到新的表中,當然這個操作只有當快滿的時候做。
實際上,兩種方法都用到兩個雜湊函式,但仔細理解可以發現,對於雙雜湊的兩個雜湊函式是巢狀的,共同決定了下一次的探測位址;而再雜湊的兩個雜湊函式是分布的,只是用來搬運乙個小的表到乙個大的表的過程。
雜湊表 再思考
雜湊表具有和陣列相同的可以根據下標實現隨機訪問的特性。陣列查詢的特性 陣列的儲存空間是連續的,因此對取值 訪問 操作比較友好,支援根據下標實現隨機訪問,時間複雜度為 o 1 雜湊表 雜湊表採用了陣列可以根據下標實現隨機訪問,時間複雜度為 o 1 的特性。問 1 那雜湊表是怎樣將陣列的特性應用到自身的...
雜湊和雜湊表 門票
時間限制 1 sec 記憶體限制 128 mb 提交 26 解決 2 提交 狀態 討論版 命題人 admin 題目描述 rpk要帶msh去乙個更加神秘的地方!rpk帶著msh穿過廣場,在第1618塊磚上按下了乙個按鈕,在一面牆上隨即出現了乙個把手。rpk握住把手,開啟了一扇石質大門。他們穿過悠長而芬...
Hash和雜湊 雜湊 表
hash又稱為雜湊,是把任意長度的輸入 又叫做預對映pre image 通過雜湊演算法變成固定長度的輸出,該輸出就是雜湊值。hash演算法還有乙個特點,就是很難找到逆向規律。在同一函式下,如果兩個雜湊值是不相同的,那麼這兩個雜湊值的原始輸入也是不同的。hash演算法又被稱為雜湊演算法。雖然被稱為演算...