JavaScript解決哈希碰撞

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章