12. 散列表(上):Word文檔中的單詞拼寫檢查功能是如何實現的

一、散列表的由來?
1.散列表來源於數組,它藉助散列函數對數組這種數據結構進行擴展,利用的是數組支持按照下標隨機訪問元素的特性。
2.需要存儲在散列表中的數據我們稱爲鍵,將鍵轉化爲數組下標的方法稱爲散列函數,散列函數的計算結果稱爲散列值。
3.將數據存儲在散列值對應的數組下標位置。
二、如何設計散列函數?
總結3點設計散列函數的基本要求
1.散列函數計算得到的散列值是一個非負整數。
2.若key1=key2,則hash(key1)=hash(key2)
3.若key≠key2,則hash(key1)≠hash(key2)
正是由於第3點要求,所以產生了幾乎無法避免的散列衝突問題。
三、散列衝突的解放方法?
1.常用的散列衝突解決方法有2類:開放尋址法(open addressing)和鏈表法(chaining)
2.開放尋址法
①核心思想:如果出現散列衝突,就重新探測一個空閒位置,將其插入。
②線性探測法(Linear Probing):
插入數據:當我們往散列表中插入數據時,如果某個數據經過散列函數之後,存儲的位置已經被佔用了,我們就從當前位置開始,依次往後查找,看是否有空閒位置,直到找到爲止。
查找數據:我們通過散列函數求出要查找元素的鍵值對應的散列值,然後比較數組中下標爲散列值的元素和要查找的元素是否相等,若相等,則說明就是我們要查找的元素;否則,就順序往後依次查找。如果遍歷到數組的空閒位置還未找到,就說明要查找的元素並沒有在散列表中。
刪除數據:爲了不讓查找算法失效,可以將刪除的元素特殊標記爲deleted,當線性探測查找的時候,遇到標記爲deleted的空間,並不是停下來,而是繼續往下探測。
結論:最壞時間複雜度爲O(n)
③二次探測(Quadratic probing):線性探測每次探測的步長爲1,即在數組中一個一個探測,而二次探測的步長變爲原來的平方。
④雙重散列(Double hashing):使用一組散列函數,直到找到空閒位置爲止。
⑤線性探測法的性能描述:
用“裝載因子”來表示空位多少,公式:散列表裝載因子=填入表中的個數/散列表的長度。
裝載因子越大,說明空閒位置越少,衝突越多,散列表的性能會下降。
3.鏈表法(更常用)
插入數據:當插入的時候,我們需要通過散列函數計算出對應的散列槽位,將其插入到對應的鏈表中即可,所以插入的時間複雜度爲O(1)。
查找或刪除數據:當查找、刪除一個元素時,通過散列函數計算對應的槽,然後遍歷鏈表查找或刪除。對於散列比較均勻的散列函數,鏈表的節點個數k=n/m,其中n表示散列表中數據的個數,m表示散列表中槽的個數,所以是時間複雜度爲O(k)。
四、思考
1.Word文檔中單詞拼寫檢查功能是如何實現的?
字符串佔用內存大小爲8字節,20萬單詞佔用內存大小不超過20MB,所以用散列表存儲20萬英文詞典單詞,然後對每個編輯進文檔的單詞進行查找,若未找到,則提示拼寫錯誤。
2.假設我們有10萬條URL訪問日誌,如何按照訪問次數給URL排序?
字符串佔用內存大小爲8字節,10萬條URL訪問日誌佔用內存不超過10MB,通過散列表統計url訪問次數,然後用TreeMap存儲散列表的元素值(作爲key)和數組下標值(作爲value)
3.有兩個字符串數組,每個數組大約有10萬條字符串,如何快速找出兩個數組中相同的字符串?
分別將2個數組的字符串通過散列函數映射到散列表,散列表中的元素值爲次數。注意,先存儲的數組中的相同元素值不進行次數累加。最後,統計散列表中元素值大於等於2的散列值對應的字符串就是兩個數組中相同的字符串。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章