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值自增+1尋找空值的索引.
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