散列表執行各類操做的時間都爲O(1),常量時間,不管散列表多大,所需時間都相同。
平均狀況下,查找與數組同樣快,插入和刪除速度與鏈表同樣快。
填裝因子: = 散列表佔用位置 / 位置總數
填裝因子越大,說明空閒位置越少,衝突越多,性能會降低。
一個小的經驗規則:一旦填裝因子大於0.7,就調整散列表的長度。
一個好的散列函數:SHA。java
數組支持按照下標隨機訪問數據的特性,散列表是數組的一種擴展,由數組演化而來。編程
開放尋址法
出現了衝突就從新探測一個空閒位置插入。
好比線性檢測:
查找的過程當中,遍歷到空閒位置結束。
刪除的時候通常不是置空,而是標記爲delete,由於置空會影響線性探測。
二次探測:二次探測和線性探測相比,探測的步長爲2。
雙重散列:不單單使用一個散列函數,若是第一個散列函數衝突,就使用第二個散列函數,依次類推。api
鏈表法
每一個元素位置再接一個鏈表。那個元素位置叫作桶或槽。多增長了鏈表的遍歷。
時間複雜度和鏈表的長度成正比。散列比較均勻的話,k = n/m,n = 數據個數,m是槽的個數。數組
詞典檢查就是把全部單詞存儲在散列表中進行查找,驗證是否能找到。空間不大,放在內存裏就行。緩存
動態擴容,均攤擴容(插入到新的散列表中,同時把老的散列表中一個數據拿到新的裏面。)服務器
當數據量比較小、裝載因子小的時候,適合採用開放尋址法。這也是Java 中的 ThreadLocalMap 使用開放尋址法的緣由。數據結構
雖然鏈表法比較耗費空間,可是若是存儲的是大對象,那麼鏈表中的結點佔用空間不多,因此能夠忽略不計。
比較適合存儲大對象,大數據量的散列表,能夠用紅黑樹代替鏈表。編程語言
默認是初始大小是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策略(最近最少使用)
散列表沒法按照某種順序快速遍歷,一個方法是拷貝到數組中,排序遍歷。 散列表是動態數據結構,不停有插入、刪除狀況。若是按照順序遍歷散列表,那麼經常會將散列表和鏈表(或者跳錶)一塊使用。