散列表(Hash table,也叫哈希表),是根據鍵(Key)而直接訪問在內存存儲位置的數據結構。也就是說,它經過計算一個關於鍵值的函數,將所需查詢的數據映射到表中一個位置來訪問記錄,這加快了查找速度。這個映射函數稱作散列函數,存放記錄的數組稱作散列表。
咱們從上圖開始分析前端
怎麼存放,分別存在哪一個槽裏?這個問題就是須要經過一個散列函數來解決了。個人存放方式是取10的餘數,咱們對應這圖來看算法
經過上面簡單的例子,應該會有一下幾點一個大體的理解數組
那麼咱們在接着看通常咱們會怎麼去取值呢?數據結構
好比咱們存儲一個key爲1000,value爲'張三' ---> {key:1000,value:'張三'}
從咱們上述的解釋,它是否是應該存放在1000%10的這個插槽裏。
當咱們經過key想要找到value張三,是否是到key%10這個插槽裏找就能夠了呢?到了這裏你能夠停下來思考一下。函數
看到這裏不知道你是否大體理解了散列函數是什麼了沒。經過例子,再經過你的思考,你能夠回頭在讀一遍文章頭部關於散列表的定義。若是你能讀懂了,那麼我估計你應該是懂了。this
處理字符串:spa
function h_str(str,M){ return [...str].reduce((hash,c)=>{ hash = (31*hash + c.charCodeAt(0)) % M },0) }
hash算法不是這裏的重點,我也沒有很深刻的去研究,這裏主要仍是去理解散列表是個怎樣的數據結構,它有哪些優勢,它具體作了怎樣一件事。
而hash函數它只是經過某種算法把key映射到列表中。設計
經過上面的解釋,咱們這裏作一個簡單的散列表3d
- 初始化散列表有多少個槽 - 用一個數組來建立M個槽
class HashTable { constructor(num=1000){ this.M = num; this.slots = new Array(num); } }
處理字符串的散列函數,這裏使用字符串是由於,數值也能夠傳換成字符串比較通用一些code
h(str){ str = str + ''; return [...str].reduce((hash,c)=>{ hash = (331 * hash + c.charCodeAt()) % this.M; return hash; },0) }
add(key,value) { const h = this.h(key); // 判斷這個槽是不是一個二維數組, 不是則建立二維數組 if(!this.slots[h]){ this.slots[h] = []; } // 將值添加到對應的槽中 this.slots[h].push(value); }
delete(key){ const h = this.h(key); this.slots[h] = this.slots[h].filter(item=>item.key!==key); }
search(key){ const h = this.h(key); const list = this.slots[h]; const data = list.find(x=> x.key === key); return data ? data.value : null; }
講到這裏,散列表的數據結構已經講完了,其實咱們每學一種數據結構或算法的時候,不是去照搬實現的代碼,咱們要學到的是思想,好比說散列表它究竟作了什麼,它是一種存儲方式,能夠快速的經過鍵去查找到對應的值。那麼咱們會思考,若是咱們設計的槽少了,在同一個槽裏存放了大量的數據,那麼這個散列表它的搜索速度確定是會大打折扣的,這種狀況又應該用什麼方式去解決,又或者是否用其餘的數據結構的代替它。
v8引擎中的數組 arr = [1,2,3,4,5] 或 new Array(100) 咱們都知道它是開闢了一塊連續的空間去存儲,而arr = [] , arr[100000] = 10 這樣的操做它是使用的散列,由於這種操做若是連續開闢100萬個空間去存儲一個值,那麼顯然是在浪費空間。
後續可能會去介紹一下二叉樹,另外對於文章有什麼寫錯或者寫的很差的地方你們均可以提出來。我會持續的去寫關於前端的一些技術文章,若是你們喜歡的話能夠關注一下,點個贊哦謝謝