数据结构与算法 / 散列表(HashTable)
一、散列思想
? ? ? ?通過散列函數通過?Key?值計算得出數組下標,然后利用數組支持下標隨機訪問的特性,在時間復雜度為O(1)的情況下找到所需要的信息。
??????????????散列函數Key?------------->?散列值(哈希值)(哈希函數)二、散列函數
? ? ? ?顧名思義,其是一個函數,函數原型大概如下:
size_t?hash(key);? ? ? ?要求,
? ? ? ?? ? ? ?1、散列值是非負整數。
? ? ? ?? ? ? ?2、若?key1?=?key2,則?hash(key1)?==?hash(key2)?。
? ? ? ?? ? ? ?3、若?key1?!=?key2,則?hash(key1)?!=?hash(key2)?。
? ? ? ?設計原則,
? ? ? ? ? ? ? 1、散列函數的設計不能太復雜,否則會消耗很多計算時間,簡介影響散列表的性能。
? ? ? ? ? ? ? 2、散列表要盡可能的隨機均勻分布。
? ? ? ?拓展,哈希算法:MD5、SHA、CRC。
三、散列沖突
? ? ? ?定義:當?key1?!=?key2?時,hash(key1)?==?hash(key2)?。
? ? ? ?解決辦法:
? ? ? ?? ? ? ?1、開放尋址法
? ? ? ?? ? ? ?? ? ? ?定義:當出現散列沖突時,在數組中重新探測一個空閑位置,將數據插入到該位置中。
? ? ? ?? ? ? ?? ? ? ?(1)線性探測(Linear?Probing)
? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?a、沖突之后,從當前位置依次向后查找(步長為1),直到找到空閑位置將數據插入到該位置。
? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?b、上述操作之后沒有發現空閑位置,則從數組的起始位置開始查找空閑位置。
? ? ? ?? ? ? ?? ? ? ?(2)二次探測
? ? ? ?? ? ? ?? ? ? ?? ? ? ?? ? ? ?與線性探測類似,唯一的不同點,線性探測探測步長為1,而二次探測的探測步長是當前步長的2次方。
? ? ? ?? ? ? ?? ? ? ?(3)雙重散列
??????? ? ? ?? ? ? ?? ? ? ?? ? ? ?存在多個散列函數,當其中一個函數出現了散列沖突,則使用第2個散列函數,依次類推,直到找到不存在散列沖突位置。
? ? ? ? ? ? ? ? ? ? ?應用場景:數據量、裝載因子較小。
?? ? ? ?? ? ? ?2、鏈表法(常用)
? ? ? ? ? ? ? ? ? ? ?在散列表中每一項不再存放數據,而是存放一個鏈表的首地址,該鏈表存放與該散列值相同的數據。時間復雜度就是這些鏈表的長度,假設為k,時間復雜度為?O(k)?。
? ? ? ? ? ? ? ? ? ? ?應用場景:數據量較大,存儲對象較大,而且可使用紅黑樹代替鏈表。
四、裝載因子(load?factor)
? ? ? ?裝載因子?=?填入表中的元素個數?/?散列表的長度?。
? ? ? ?裝載因子越大,則空閑位置越少,沖突越多,散列表的性能就越低,時間復雜度最壞情況從?O(1)?降到?O(n)?。
? ? ? ?當裝載因子過大時,需要動態擴容,時間復雜度為O(n)。當裝載因子過小時,需要動態縮容,時間復雜度為O(n)。上述操作如果對于數據量較小時耗時不是很明顯,但是對于數據量很大的情況,比如1個G,那么插值的時間就很漫長,因為要將1G的數據遷移過來。所以為了避免上述情況的發生,可以將遷移數據的情況分散在之后的每一個插入數據的過程中,這樣時間復雜度就變成了O(1)。在查找的情況下,先去舊的散列表中查找,沒有發現則到新的散列表中查找,同理縮容。
五、散列表碰撞攻擊的原理
? ? ? ?對于使用鏈表法解決散列沖突的散列表,攻擊者精心制作數據,使得這些數據全部都散列到散列表同一個位置,導致散列? 表退化為鏈表,時間復雜度直接將為了O(n)。查詢的過程中直接導致CPU資源耗盡,導致服務器無法相應其他需求。
六、設計工業級散列表的要點
? ? ? ?要求:
? ? ? ? ? ? ? 1、支持快速的插入、刪除、查找操作。
? ? ? ? ? ? ? 2、內存占用合理。
? ? ? ? ? ? ? 3、性能穩定,極端情況下不會退化到無法接受的程度。
? ? ? ?設計方向:
? ? ? ? ? ? ? 1、設計合適的散列函數。
? ? ? ? ? ? ? 2、定義裝載因子并且設計動態擴容策略。
? ? ? ? ? ? ? 3、選擇合適的散列沖突的方法。
七、散列表的應用
?1、Office?Word?中拼寫檢查功能。
? ? ? ?當用戶拼寫完一個單詞之后,word會檢查該單詞是否是正確的,方法是開發人員將所有的單詞存入內存中,存儲規則是將單詞做為?Key,通過相應的散列函數,計算出散列值,然后將單詞報錯到該散列值對應的位置中。當用戶拼寫完單詞之后,直接在內存中查找是否存在該單詞,若存在說明拼寫成功,否則拼寫失敗。
2、假設有10萬條 URL 訪問日志,如何按照訪問次數給 URL 排序。
? ? ? ?遍歷10萬條數據,以 URL 為 Key ,訪問次數為 Value ,存入散列表中,時間復雜度為 O(n) ,之后通過相應的排序算法進行排序即可。
?
(SAW:Game Over!)
總結
以上是生活随笔為你收集整理的数据结构与算法 / 散列表(HashTable)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cpp 对象模型探索 / 编译器为对象创
- 下一篇: 数据结构与算法 / 哈希算法