在字典(或映射)中,用【键/值】对的形式来存储数据。
// 如果item变量是一个对象的话,需要实现toString方法,否则会导致出现异常的输出结果,如"[object Object]"。 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 Dictionary { constructor(toStrFn = defaultToString){ this.toString = toStrFn this.table = {} } } Dictionary.prototype.hasKey = function(key){ return this.table[this.toStrFn(key)] != undefined } Dictionary.prototype.set = function(key,value){ if(key != null && value != null){ const tableKey = this.toStrFn(key) this.table[tableKey] = new ValuePair(key,value) return true } return false } Dictionary.prototype.remove = function(key){ if(this.hasKey(key)){ delete this.table[this.toStrFn(key)] return true } return false } Dictionary.prototype.get = function(key){ const valuePair = this.table[this.toStrFn(key)] return valuePair == null ? undefined : valuePair.value // if(this.hasKey(key)){ // return this.table[this.toStrFn(key)] // } // return undefined } Dictionary.prototype.keyValues = function(){ return Object.value(this.table) // const vaulePairs = [] // for(let k in this.table){ // if(this.hasKey(k)){ // vaulePairs.push(this.table[k]) // } // } // return valuePairs } Dictionary.prototype.keys = function(){ return this.keyValues().map(valuePair => valuePair.key) } Dictionary.prototype.values = function(){ return this.keyValues().map(valuePair => valuePair.value) } Dictionary.prototype.foreach = function(callback){ const valuePairs = this.keyValues() for(let i = 0;i < valuePair.length;i++){ let item = valuePair[i] const result = callback(item.key,item.value) if(result == false){ break } } } Dictionary.prototype.size = function(){ return Object.keys(this.table).length } Dictionary.prototype.isEmpty = function(){ return this.size() === 0 } Dictionary.prototype.clear = function(){ this.table = {} } Dictionary.prototype.toStrFn = function(){ if(this.isEmpty){ return '' } const valuePairs = this.keyValues() let baseStr = `${valuePairs[0].toString()}` for(let i = 1;i < valuePairs.length;i++){ baseStr = `${baseStr},${valuePairs[i].toString()}` } return baseStr }
散列算法的作用是尽可能快地在数据结构中找到一个值。散列函数的作用是给定一个键值,然后返回值在表中的地址。
class HashTable { constructor(toStrFn = defaultToString){ this.toString = toStrFn this.table = {} } } HashTable.prototype.loseHashCode = function(key){ if(typeof key === 'number'){ return key } const tableKey = this.toStrFn(key) let hash = 5381 for(let i = 0;i < tableKey.length;i++){ hash = hash * 33 + tableKey.charCodeAt(i) } return hash % 1013 } HashTable.prototype.hashCode = function(key){ return this.loseHashCode(key) } HashTable.prototype.put = function(key,value){ if(key != null && value != null){ const pos = this.hashCode(key) this.table[pos] = new ValuePair(key,value) return true } return false } HashTable.prototype.get = function(key){ const valuePair = this.table[this.toStrFn(key)] return valuePair == undefined ? undefined : valuePair.value } HashTable.prototype.remove = function(key){ const hash = this.hashCode(key) const valuePair = this.table[hash] if(valuePair != null){ delete this.table[hash] return true } return false }
处理散列表中的冲突(哈希冲突)
- 分离链接发包括为散列表的每一个位置创建一个链表并将原宿存储在里面。它是解决冲突的最简单的方法,但是在HashTable实例之外还需要额外的空间
- 线性探查是因为处理冲突的方法是将元素直接存储到表中,而不是在单独的数据结构中。当向表中的某个位置添加一个新元素时,如果索引为position的位置已经被占据了,就尝试position+1的位置。以此类推,直到在散列表中找到一个空闲的位置。