We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
这个玩意有无数个别名: map/dict/object/hashTable
map
dict
object
hashTable
需求:
setItem(key, value)
getItem(key)
null
思路: 首先需要一个数组来存取所有的 key-value, 取名table
table
然后最简单的, 写一个函数hashStringToInt(s), 该函数接受字符串为参数, 返回的是经过hash过的数字. 对应到实现 hashTable, 将 key 传入到该函数, 得到的结果即为对应table的索引, 然后在对应索引下存入 value, 如下
hashStringToInt(s)
hash
// 三个 key-value 以及对应的 hash 值 key hash value name 0 'a' age 2 '18' height 3 169 // table 最后为 ['a', undefined, '18', 169, ...]
但是这样做存在两个问题:
100
hashStringToInt(key)
table.length
方法为, 将出现冲突的 index 的位置的元素, 改成一个数组, 该数组存取所有 hash 结果和该索引一样的 key-value, 形式也为一个数组, 如下
// 三个 key-value 以及对应的 hash 值 // 其中 name 和 gae hash 冲突, 均为 0 key hash value name 0 'a' age 0 '18' height 3 169 // table 最后为 [[['name', 'a'], ['age', '18']], undefined, undefined, [[['height', 169]]]]
到这里基本上没有什么问题了, 但是性能还是要考虑一下, 运气不好你甚至可能出现你想存的所有 key-value 对所对应的 hash 都是同一个...那么该 index 下就会存在 n(n 可以是 9999999...) 个 key-value 组合, 然后最坏情况就是你遍历 n 次, 然后找到了最后一个才是你想要的
所以比较好的情况还是能够比较均匀的将 key-value 分布到各个 index, 每个 index 下可能只存 1-3 个 key, value, 那么查找的时候最坏也就查 3 次找到, 相比 9999999 实在好很多
要实现这一功能, 其实很简单, 增加一个loadFactor系数, 为存取的 key-value 数量 / table length, 这里可以设定当loadFactor大于 0.8 的时候, 增加table的容量, 将容量扩大到下一个质数
loadFactor
存取的 key-value 数量 / table length
同时最后还要注意一个问题, 当对同一个 key 进行写入的时候, 如果是不同的 value, 则更新 value, 如果还是同一个 value, 不做任何操作, 因此需要做一些判断
完整代码如下:
class HashTable { constructor() { this.table = new Array(3) this.numItems = 0 } hashStringToInt(s, tableSize) { let hash = 17 for (let i = 0; i < s.length; i++) { hash = (13 * hash * s.charCodeAt(i)) % tableSize } return hash } resize() { // 使用 Mersenne prime 得到下一个 prime, 肮脏实现 const newTable = new Array(2 ** this.table.length - 1) // rehash all for (const e of this.table) { if (e) { // 存在该 index 下的元素是 undefined 的可能性... for (const [key, value] of e) { const index = this.hashStringToInt(key, newTable.length); if (newTable[index]) { newTable[index].push([key, value]); } else { newTable[index] = [[key, value]]; } } } } this.table = newTable } getItem(key) { const index = this.hashStringToInt(key, this.table.length) if (!this.table[index]) { return null } return this.table[index].find(e => e[0] === key)[1] } setItem(key, value) { const loadFactor = this.numItems / this.table.length if (loadFactor > 0.8) { // resize this.resize() } const index = this.hashStringToInt(key, this.table.length) if (this.table[index]) { // 判断是否在设置同一个 key const item = this.table[index].find(e => e[0] === key) if (item) { // 相同即更新 item[1] = value } else { // 否则添加新元素 this.numItems++ this.table[index].push([key, value]) } } else { this.numItems++ this.table[index] = [[key, value]] } } } const hashTable = new HashTable() hashTable.setItem('A', 'a') hashTable.setItem('B', 'b') hashTable.setItem('A', 'a1') hashTable.setItem('C', 'c') hashTable.setItem('D', 'd') console.log(hashTable.numItems) // 4 console.log(hashTable.table.length) // 7 console.log(hashTable.getItem('A')) // a1 console.log(hashTable.getItem('B')) // b console.log(hashTable.getItem('C')) // c console.log(hashTable.getItem('D')) // d
The text was updated successfully, but these errors were encountered:
No branches or pull requests
简单实现一个 hashtable
这个玩意有无数个别名:
map
/dict
/object
/hashTable
需求:
setItem(key, value)
写入键值对(key-value), 当写入的是相同的键但不同的值时, 为更新, 当重复写入同样的键值对, 不做任何操作(即不会存在重复将一个键值对存两遍, 也不会存在同一个键对应多个不同的值)getItem(key)
根据键名得到值, 当读取不存在的键名是, 抛出null
思路:
首先需要一个数组来存取所有的 key-value, 取名
table
然后最简单的, 写一个函数
hashStringToInt(s)
, 该函数接受字符串为参数, 返回的是经过hash
过的数字. 对应到实现 hashTable, 将 key 传入到该函数, 得到的结果即为对应table
的索引, 然后在对应索引下存入 value, 如下但是这样做存在两个问题:
table
的时候, 一般会固定一个值, 假设为100
(有效的索引最多到 99),hashStringToInt(key)
很有可能是超过 99 的. 这个时候可以对最后的结果取table.length
的模, 即这样无论如何最后 hash 出来的结果都不会超过table.length
(这里是 99)方法为, 将出现冲突的 index 的位置的元素, 改成一个数组, 该数组存取所有 hash 结果和该索引一样的 key-value, 形式也为一个数组, 如下
到这里基本上没有什么问题了, 但是性能还是要考虑一下, 运气不好你甚至可能出现你想存的所有 key-value 对所对应的 hash 都是同一个...那么该 index 下就会存在 n(n 可以是 9999999...) 个 key-value 组合, 然后最坏情况就是你遍历 n 次, 然后找到了最后一个才是你想要的
所以比较好的情况还是能够比较均匀的将 key-value 分布到各个 index, 每个 index 下可能只存 1-3 个 key, value, 那么查找的时候最坏也就查 3 次找到, 相比 9999999 实在好很多
要实现这一功能, 其实很简单, 增加一个
loadFactor
系数, 为存取的 key-value 数量 / table length
, 这里可以设定当loadFactor
大于 0.8 的时候, 增加table
的容量, 将容量扩大到下一个质数同时最后还要注意一个问题, 当对同一个 key 进行写入的时候, 如果是不同的 value, 则更新 value, 如果还是同一个 value, 不做任何操作, 因此需要做一些判断
完整代码如下:
参考
The text was updated successfully, but these errors were encountered: