對於長度爲n的哈希表,它的存儲過程以下: 根據 key 計算出它的哈希值 h=hash(key) 假設箱子的個數爲 n,那麼這個鍵值對應該放在第 (h % n) 個箱子中 若是該箱子中已經有了鍵值對,就使用開放尋址法或者拉鍊法解決衝突
若是不一樣字符串被hash到了同一個位置,稱爲哈希衝突。解決哈希衝突的經常使用辦法有如下幾種:html
拉鍊法(開哈希)java
在使用拉鍊法解決哈希衝突時,對於每個數組位置,放置的元素至關於一個鏈表,屬於同一個箱子的全部鍵值對都會排列在鏈表中。當有衝突時,咱們將這個元素插入到鏈表尾部,以此來避免衝突。python
線性探測法(閉哈希)面試
線性探測法屬於開放定址法的一種。 算法
當衝突發生的時候,咱們檢查衝突的哈希地址的下一位(數組下標加一),判斷可否插入,若是不能則再繼續檢查下一個位置。api
在拉鍊法實現的哈希表中,由於鏈表的存在,能夠彈性地容納鍵值對,而對於線性探測法實現的哈希表,其容納鍵值對的數量是直接受到數組大小的限制的。因此必須在數組充滿之前調整數組的大小。通常來講,每當總鍵值對的對數達到數組的一半後,咱們就將整個數組的大小擴大一倍。數組
閉哈希用的很少,由於一直往下一位插入會致使愈來愈多的collision數據結構
重哈希oracle
這種方法是同時構造多個不一樣的哈希函數:分佈式
Hi=RH1(key) i=1,2,…,k
當哈希地址Hi=RH1(key)發生衝突時,再計算Hi=RH2(key)……,直到衝突再也不產生。這種方法不易產生彙集,但增長了計算時間。
哈希表的擴容
通常來講,每當總鍵值對的對數達到數組的一半後,咱們就將整個數組的大小擴大一倍。擴容時要把全部的元素從新計算hash並插入到更大容量的新哈希表中。
參考DHT,將一張哈希表按hash值分割到不一樣機器上。
在普通分佈式哈希表中,若是有節點動態加入或者刪除,就會致使大量數據失效。那麼如何改進這一狀況呢?
consistent hashing 是一種 hash 算法,簡單的說,在移除 / 添加一個 cache 時,它可以儘量小的改變已存在 key 映射關係。它的思想是把機器和數據都hash到同一個空間中。
好比在Chord算法裏,每臺節點負責它順時針方向到下一個節點以前的這一區域的hash數據點。若是在這一區間內有節點的動態加入/刪除,那麼只有這一區間端點的兩臺機器會受影響,而其餘機器都不會。
另外還有一種DHT算法叫作Kademlia,它就是P2P下載的基礎。能夠參考https://colobu.com/2018/03/26/distributed-hash-table/
紅黑樹(Red-black Tree)是一種平衡排序二叉樹(Balanced Binary Search Tree),在它上面進行增刪查改的平均時間複雜度都是 O(logn),是居家旅行的常備數據結構。
Q: 在面試中考不考呢?
A: 不多考……
Q: 需不須要了解呢?
A: 須要!
Q: 瞭解到什麼程度呢?
A: 知道它是 Balanced Binary Search Tree,知道它支持什麼樣的操做,會用就行。不須要知道具體的實現原理。
Java當中,紅黑樹主要是TreeSet
,位於java.util.TreeSet
,繼承自java.util.AbstractSet
,它的主要方法有:
add
,插入一個元素。remove
,刪除一個元素。clear
,刪除全部元素。contains
,查找是否包含某元素。isEmpty
,是否空樹。size
,返回元素個數。iterator
,返回迭代器。clone
,對整棵樹進行淺拷貝,即不拷貝元素自己。first
,返回最前元素。last
,返回最末元素。floor
,返回不大於給定元素的最大元素。ceiling
,返回不小於給定元素的最小元素。pollFirst
,刪除並返回首元素。pollLast
,刪除並返回末元素。更具體的細節,請參考Java Reference。
此外,在Java當中,有一種map,用紅黑樹實現key查找,這種結構叫作TreeMap
。若是你須要一種map,而且它的key是有序的,那麼強烈推薦TreeMap
。
在C++當中,紅黑樹便是默認的set
和map
,其元素也是有序的。
而經過哈系表實現的則分別是unordered_set
和unordered_map
,注意這兩種結構是在C++11
纔有的。
在Python當中,默認的set和dict是用哈系表實現,沒有默認的紅黑樹。若是你想使用紅黑樹的話,可使用rbtree
這個模塊,下載地址:https://pypi.python.org/pypi/rbtree/0.9.0