散列表(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万个空间去存储一个值,那么显然是在浪费空间。
后续可能会去介绍一下二叉树,另外对于文章有什么写错或者写的很差的地方你们均可以提出来。我会持续的去写关于前端的一些技术文章,若是你们喜欢的话能够关注一下,点个赞哦谢谢