極客時間課程《數據結構與算法之美》筆記06 - 散列表

散列表(Word文檔中的單詞拼寫檢查功能)

優點

  • 模擬映射關係
  • 防止重複
  • 緩存、記住數據,以避免服務器再經過處理生成。
  • 查找、插入、刪除都很是快。
  • 能夠結合散列函數和數組來建立散列表,通常編程語言都提供了實現。

散列表執行各類操做的時間都爲O(1),常量時間,不管散列表多大,所需時間都相同。
平均狀況下,查找與數組同樣快,插入和刪除速度與鏈表同樣快。
填裝因子: = 散列表佔用位置 / 位置總數
填裝因子越大,說明空閒位置越少,衝突越多,性能會降低。
一個小的經驗規則:一旦填裝因子大於0.7,就調整散列表的長度。
一個好的散列函數:SHA。java

思想

數組支持按照下標隨機訪問數據的特性,散列表是數組的一種擴展,由數組演化而來。編程

散列衝突

  • 開放尋址法
    出現了衝突就從新探測一個空閒位置插入。
    好比線性檢測
    查找的過程當中,遍歷到空閒位置結束。
    刪除的時候通常不是置空,而是標記爲delete,由於置空會影響線性探測。
    二次探測:二次探測和線性探測相比,探測的步長爲2。
    雙重散列:不單單使用一個散列函數,若是第一個散列函數衝突,就使用第二個散列函數,依次類推。api

  • 鏈表法
    每一個元素位置再接一個鏈表。那個元素位置叫作桶或槽。多增長了鏈表的遍歷。
    時間複雜度和鏈表的長度成正比。散列比較均勻的話,k = n/m,n = 數據個數,m是槽的個數。數組

詞典檢查就是把全部單詞存儲在散列表中進行查找,驗證是否能找到。空間不大,放在內存裏就行。緩存

工業級散列表設計

動態擴容,均攤擴容(插入到新的散列表中,同時把老的散列表中一個數據拿到新的裏面。)服務器

當數據量比較小、裝載因子小的時候,適合採用開放尋址法。這也是Java 中的 ThreadLocalMap 使用開放尋址法的緣由。數據結構

雖然鏈表法比較耗費空間,可是若是存儲的是大對象,那麼鏈表中的結點佔用空間不多,因此能夠忽略不計。
比較適合存儲大對象,大數據量的散列表,能夠用紅黑樹代替鏈表。編程語言

HashMap 分析

默認是初始大小是16,能夠調節。
最大裝載因子是0.75,啓動擴容會擴大到兩倍大小。函數

底層使用鏈表法解決衝突,JDK1.8版本中,鏈表長度超過8時,鏈表轉化爲紅黑樹。當紅黑樹結點少於8個的時候,紅黑樹轉化爲鏈表。性能

如下爲其散列函數。

int hash(Object key) {
    int h = key.hashCode();//返回Java對象的hash code
    return (h ^ (h >>> 16)) & (capitity -1); //capicity 表示散列表的大小
}

散列表和鏈表的結合

添加、刪除、查找操做時間複雜度降到O(1)。
散列表中嵌入雙向鏈表,雙向鏈表增長特殊字段hnext。
結點除了可使用前驅後繼指針訪問以外,還能夠經過hnext索引訪問(拉鍊)。
疑惑點:爲什麼查找到一個結點以後將其放在鏈表尾部。

Redis有序集合
Redis和跳錶關係很緊密

Java LinkedHashMap
LinkedHashMap能夠支持按照插入順序遍歷數據,還支持按照訪問順序來遍歷數據。
Linked指的是雙向鏈表。
訪問完數據以後也會放到鏈表結尾,估計是LRU策略(最近最少使用)

小結

散列表沒法按照某種順序快速遍歷,一個方法是拷貝到數組中,排序遍歷。 散列表是動態數據結構,不停有插入、刪除狀況。若是按照順序遍歷散列表,那麼經常會將散列表和鏈表(或者跳錶)一塊使用。

相關文章
相關標籤/搜索