这是我参与更文挑战的第23天,活动详情查看:更文挑战
冲突解决
1. 书写更好的散列函数
既然我们知道了冲突是由于在创建之初由于散列函数给出了相同的hash导致的,那么根源的上的解决办法就是重写一个更好的不会返回重复hash值的散列函数,从而避免冲突。
而一个表现良好的散列函数是由几个方面构成的:插入和检索元素的时间(即性能),也包括较低的冲突的可能性。 举个🌰:
let dib2HashCode = function (key) {
// 初始化hash变量值为5381
let hash = 5381
// 迭代参数key,将hash乘以33并和当前迭代到的字符的ASCII码值相加
for(let i = 0; i < key.length; i++) {
hash = hash * 33 + key.charCodeAt(i)
}
// 最后取余
return hash % 1013
}
2. 线性探查 线性探查就是:当想向散列表中的某个位置加入一个新元素的时候,如果索引为index的位置已经被占据了,就尝试index+1位置,如果index+1的位置也被占据了那么就尝试idnex+2的位置,以此类推。
简单来说就是从index位置开始挨个试,一个不行就换下一个,直到找到空余的位置。
看代码:
function HashTable () {
let table = []
let loseloseHashCode = function (key) {
let hash = 0
// 使用组成key的每个字符的ASCII码值
for (let i = 0; i < key.length; i++) {
hash += key.charCodeAt(i)
}
return hash % 37
}
// 辅助类
let ValuePair = function (key, value) {
this.key = key
this.value = value
}
this.put = function (key, value) {
let position = loseloseHashCode(key)
if (!table[position]) {
table[position] = new ValuePair(key, value)
} else {
// 此处position位置已有元素占据,那么直接从positon+1位置处开始遍历查找
let index = ++position
while (table[index]) {
// 迭代index
index++
}
// 循环体外说明该index位置是undefined意味着可以存放新值
table[index] = new ValuePair(key, value)
}
}
this.get = function (key) {
let position = loseloseHashCode(key)
if(table[position]) {
if (table[position].key === key) {
return table[position].value
} else {
let index = ++position
while (table[index] && table[index]?.key !== key) {
index++
}
if(table[index] && table[index]?.key === key) {
return table[index].value
}
}
}
return undefined
}
this.remove = function (key) {
let position = loseloseHashCode(key)
if(table[position]) {
if (table[position].key === key) {
table[position] = undefined
} else {
let index = ++position
while (table[index] && table[index]?.key !== key) {
index++
}
if(table[index] && table[index]?.key === key) {
table[index] = undefined
}
}
}
return false
}
}
至此,我们已经有三种方式解决散列表的冲突了:
- 分离链接
- 线性探查
- 创建更好的散列函数