Hash的基本实现
定义Hash类
function Hash() {
this.hash = new Array(128)
this.simpleHash = function(key) {
// key为字符串
let total = 0
for(let i = 0;i < key.length;i++) {
total += key.charCodeAt(i) * 10086
}
return total % this.hash.length
}
this.put = function(key, value) {
let pos = this.simpleHash(key)
this.hash[pos] = value
}
this.show = function() {
for(let i = 0;i < this.hash.length;i++) {
this.hash[i] ? console.log(`${i}: `, this.hash[i]) : ''
}
}
}
不同键值可能得到相同的hash值,如下:
let myHash = new Hash()
myHash.put('bc','I am curry')
myHash.put('I am the key...','I am the bucket...')
// 产生hash碰撞
myHash.put('ad','I am kyrie')
myHash.show()
哈希碰撞解决方法
开链法
每个对应Hash值的Hash Bucket对应一个链表(此处用二维数组模拟),链表中存储着键值对应的JSON数据,从而获取不同key时相同hash值情况下的bucket
function Hash1() {
this.hash = new Array(128)
for(let i = 0;i < this.hash.length;i++) {
this.hash[i] = []
}
this.simpleHash = function(key) {
// key为字符串
let total = 0
for(let i = 0;i < key.length;i++) {
total += key.charCodeAt(i) * 10086
}
return total % this.hash.length
}
// hash值相同则加入该hash值的链表中
this.put = function(key, value) {
let index = 0
let pos = this.simpleHash(key)
if(!this.hash[pos][index]) {
let jsonStr = `{"${key}" : "${value}"}`
this.hash[pos][index] = JSON.parse(jsonStr)
} else {
index++
while(this.hash[pos][index]) {
index++
}
let jsonStr = `{"${key}" : "${value}"}`
this.hash[pos][index] = JSON.parse(jsonStr)
}
}
this.get = function(key) {
let pos = this.simpleHash(key)
let index = 0
// 判断是否存在hash bucket
if(typeof this.hash[pos][index] === 'object') {
// 获取相同hash值的不同key值对应的bucket
if(this.hash[pos][index][key]) {
return this.hash[pos][index][key]
} else {
while(typeof this.hash[pos][index] === 'object') {
if(this.hash[pos][index][key]) {
break
}
index++
}
return this.hash[pos][index][key]
}
} else {
return "this key isn't exist"
}
}
}
调试
let myHash1 = new Hash1()
myHash1.put('bc','I am curry')
myHash1.put('I am the key...','I am the bucket...')
// 产生hash碰撞
// hash值都为126
myHash1.put('ad','I am kyrie')
console.log(myHash1.hash[126]) //[ { bc: 'I am curry' }, { ad: 'I am kyrie' } ]
console.log('开链法:', myHash1.get('ad')) //开链法: I am kyrie
线性探测
开发寻址散列,若发生hash碰撞,则当前key的hash值自增向下寻找空值的索引.
function Hash2() {
// hash存储唯一键值
// bucket存取键值对应的bucket
this.hash = new Array(128)
this.bucket = new Array(128)
this.simpleHash = function(key) {
// key为字符串
let total = 0
for(let i = 0;i < key.length;i++) {
total += key.charCodeAt(i) * 10086
}
return total % this.hash.length
}
this.put = function(key, value) {
let pos = this.simpleHash(key)
if(!this.hash[pos]) {
// 存储唯一键值
this.hash[pos] = key
// 存取bucket
this.bucket[pos] = value
} else {
while(this.hash[pos]) {
if(pos < this.hash.length) {
pos++
}
else {
console.error('full..')
return
}
}
this.hash[pos] = key
this.bucket[pos] = value
}
}
this.get = function(key) {
let pos = this.simpleHash(key)
while(this.hash[pos]) {
if(this.hash[pos] === key) {
return this.bucket[pos]
}
pos++
}
return 'not exist'
}
}
调试:
let myHash2 = new Hash2()
myHash2.put('bc','I am curry')
myHash2.put('I am the key...','I am the bucket...')
// 产生hash碰撞
// hash值都为126
myHash2.put('ad','I am kyrie')
console.log('线性探测:',myHash2.get('ad')) // 线性探测: I am kyrie