HashTable
function defaultToString(item) {
if (item === null) {
return 'NULL';
} else if (item === undefined) {
return 'UNDEFINED';
} else if (typeof item === 'string' || item instanceof String) {
return `${item}`;
}
return item.toString();
}
class ValuePair {
constructor (key, value) {
this.key = key
this.value = value
}
toString () {
return `[#${this.key}: ${this.value}]`
}
}
class HashTable {
constructor(toStrFn = defaultToString) {
this.toStrFn = toStrFn
this.table = {}
}
// 創建散列函數
loseloseHashCode (key) {
if (typeof key === 'number') return key
const tableKey = this.toStrFn(key)
let hash = 0
for (let i = 0; i < tableKey.length; i++) {
hash += tableKey.charCodeAt(i)
}
return hash % 37
}
hashCode (key) {
return this.loseloseHashCode(key)
}
// 更新 或 新增
put (key, value) {
if (key != null && value != null) {
this.table[this.toStrFn(key)] = new ValuePair(key, value)
return true
}
return false
}
remove (key) {
const hash = this.hashCode(key)
const valuePair = this.table[hash]
if (valuePair != null) {
delete this.table[hash]
return true
}
return false
}
get (key) {
const valuePair = this.table[this.hashCode(key)]
return valuePair == null ? undefined : valuePair.value
}
toString () {
if (this.isEmpty()) return ''
const keys = Object.keys(this.table)
let objString = `{${keys[0]} => ${this.table[keys[0].toString()]}}`
for (let i = 1; i < keys.length; i++) {
objString = `${objString},{${keys[i]} => ${this.table[keys[i].toString()]}}`
}
return objString
}
}
解决哈希冲突:分离链接,线性探索,双散列
- 分离链接
class HashTableSeparateChaining {
constructor(toStrFn = defaultToString) {
this.toStrFn = toStrFn
this.table = {}
}
put (key, value) {
if (key != null && value != null) {
const position = this.hashCode(key)
if (this.table[position] == null) {
this.table[position] = new LinkedList()
}
this.table[position].push(new ValuePair(key. value))
return true
}
return false
}
get (key) {
const position = this.hashCode(key)
const linkedList = this.table[position]
if (linkedList != null && !linkedList.isEmpty()) {
let current = linkedList.getHead()
while (current != null) {
if (current.element.key === key) {
return current.element.value
}
current = current.next
}
}
return undefined
}
remove (key) {
const position = this.hashCode(key)
const linkedList = this.table[position]
if (linkedList != null && !linkedList.isEmpty()) {
let current = linkedList.getHead()
while (current != null) {
if (current.element.key === key) {
linkedList.remove(current.element)
if (linkedList.isEmpty()) {
delete this.table[position]
}
return true
}
current = current.next
}
}
return false
}
}
- 线性探索
put (key, value) {
if (key != null && value != null) {
const position = this.hashCode(key)
if (this.table[position] == null) {
this.table[position] = new ValuePair(key, value)
} else {
let index = position + 1
while (this.table[index] != null) {
index++
}
this.table[index] = new ValuePair(key, value)
}
return true
}
return false
}
get (key) {
const position = this.hashCode(key)
if (this.table[position] != null) {
if (this.table[position].key === key) {
return this.table[position].value
}
let index = position + 1
while (this.table[index] != null && this.table[index].key !== key) {
index++
}
if (this.table[index] != null && this.table[index].key === key) {
return this.table[index].value
}
}
return undefined
}
remove (key) {
const position = this.hashCode(key)
if (this.table[position] != null) {
if (this.table[position].key === key) {
delete this.table[position]
this.verifyRemoveSideEffect(key, position)
return true
}
let index = position + 1
while (this.table[index] != null && this.table[index].key !== key) {
index++
}
if (this.table[index] != null && this.table[index].key === key) {
delete this.table[index]
this.verifyRemoveSideEffect(key, position)
return true
}
}
return false
}
verifyRemoveSideEffect (key, removePosition) {
const hash = this.hashCode(key)
let index = removePosition + 1
while (this.table[index] != null) {
const posHash = this.hashCode(this.table[index].key)
if (posHash <= hash || posHash <= removePosition>) {
this.table[removedPosition] = this.table[index]
delete this.table[index]
removePosition = index
}
index++
}
}
- 创建更好的散列函数: 社区最受推崇的散列函数之一
djb2HashCode (key) {
const tableKey = this.toStrFn(key)
let hash = 5381
for (let i=0; i < tableKey.length>; i++) {
hash = (hash*33) + tableKey.charAt(i)
}
return hash % 1013
}