哈希表基础知识
哈希表,又叫散列表(HashTable或者HashMap),是根据键直接访问记录在存储位置的数据结构,通过哈希函数根据计算出在哈希表中的内存地址
作用是尽可能快地在数据结构中找到一个值
实现哈希表
实现方法
- get(val)
- put(key, val)
- remove(key)
手写实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| class ValuePair { constructor(key, val) { this.key = key; this.val = val; }; toString() { return `[${this.key}:${this.val}]`; } }
class HashTable { constructor(toStrFn) { this.table = {}; } loseloseHashTable(key) { if (typeof key === 'number') { return key; } const tablekey = String(key); let hash = 0; for (let i = 0; i < tableKey.length; i++) { hash += tablekey.charCodeAt(i); } return hash % 37; } hashCode(key) { return this.loseloseHashTable(key); } put(key, val) { if (key !== null && val !== null) { const position = this.hashCode(key); this.table[position] = new ValuePair(key, val); return true; } return false; } get(key) { const valuePair = this.table[this.hashCode(key)]; return valuePair = valuePair ? valuePair.val : undefined; } remove(key) { const hash = this.hashCode(key); const valuePair = this.table[hash]; if (valuePair) { delete this.table[hash]; return true; } return false; } }
|
测试一下子~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const hash = new HashTable();
hash.put('Katrina', '111.com'); hash.put('Jenny', '222.com'); hash.puth('Kate', '333.com');
console.log(hash.hashCode('Katrina') + '-Katrina'); console.log(hash.hashCode('Jenny') + '-Jenny'); console.log(hash.hashCode('Kate') + '-Kate');
console.log(hash.get('Katrina')); console.log(hash.get('Lisa'));
hash.remove('Kate'); console.log(hash.get('Kate'));
|
哈希表和哈希集合
处理哈希表中的冲突
一些键会有相同的hash值,比如hash.hashCode('Jenny')
和hash.hashCode('Jisoo')
都是35,一般来说,具有相同hash值的数据在hash表中值会被替换
看下面的代码:
1 2 3 4 5 6 7 8 9
| const hash = new HashTable();
hash.put('Jisoo', '111.com'); hash.put('Jenny', '222.com');
console.log(hash.hashCode('Jisoo') + '-Jisoo'); console.log(hash.hashCode('Jenny') + '-Jenny');
console.log(hash.get('Jisoo'));
|
处理冲突的方法有:分离链接、线性探查、双散列法
1. 分离链接
分离链接指的是为哈希表的每一个位置创建一个链表并且要将元素存储在里面
重写put方法
重写思路:验证要加入的新元素的位置是否已经被占据,如果已经占据,会创建一个NodeList实例,将ValuePair加入到这个实例
重写get
重写思路:验证能否在特定位置找到该元素,定位后,通过遍历ListNode得到元素,没有找到就返回undefined
重写remove
重写思路:类似于定位后找到链表,然后去删除链表中的节点
2. 线性探查
将元素直接存到表中,而不是在单独的数据结构中
重写思路和put基本相同,不再赘述
3. 双散列法
创建更好地散列函数:1. 插入和检索元素的时间;2. 较低的冲突可能性
比lose lose哈希函数更好的函数是djb2
1 2 3 4 5 6 7 8
| djb2HashCode(key) { const tableKey = String(key); let hash = 5381; for (let i = 0; i < table.length; i++) { hash = (hash * 33) + tableKey.charCodeAt(i); } return hash % 1013; }
|
参考
代码随想录_哈希表