// 基于数组封装一个哈希表
function HashTable() {
// 属性
this.storage = [];
this.count = 0; // 数据的存储量
this.limit = 7; // 容量长度最好为质数,利于数据在容器中均匀分布
// -----------------方法------------
// 哈希函数
HashTable.prototype.hashFunc = function (str,size) {
// 定义一个hashCode
let hashCode = 0;
// 霍纳算法 计算尽可能多加减,少乘除,提高运算效率
for (var i = 0; i < str.length; i++) {
hashCode = hashCode * 37 + str.charCodeAt(i)
}
// 范围压缩 求余获得位置下标
let index = hashCode % size;
return index
}
// 新增&修改
HashTable.prototype.put = function(key,value){
// 1.通过哈希函数获取到存储位置的下标
let index = this.hashFunc(key,this.limit);
// 2.判断这个位置是否有存储内容
this.storage[index] = this.storage[index] == null ? [] : this.storage[index];
// 3.判断是修改还是新增
for(let i = 0;i < this.storage[index].length;i++){
// 修改
if(this.storage[index][i][0] === key){
this.storage[index][i][1] = value;
return
}
}
// 新增
this.storage[index].push([key,value]);
// 4.存储数量+1
this.count++;
// 5.判断是否需要扩容
if(this.count > this.limit * 0.75){
this.resize(this.getPrime(this.limit * 2))
}
}
// 获取
HashTable.prototype.get = function(key){
// 1.通过哈希函数获取到位置下标
let index = this.hashFunc(key,this.limit);
// 2.判断此位置处是否为空
let bucket = this.storage[index];
if(bucket == null) return null;
// 3.线性查找此位置中存储的数据
for(let i = 0; i < bucket.length;i++){
// 找到返回数据
if(bucket[i][0] === key){
return bucket[i][1]
}
}
// 没找到返回null
return null
}
// 删除
HashTable.prototype.remove = function(key){
// 1.通过哈希函数获取到index
let index = this.hashFunc(key,this.limit);
// 2.判断此位置是否为null
let bucket = this.storage[index];
if(bucket == null) return null;
// 3.遍历找对应的数据
for(let i = 0; i < bucket.length;i++){
let tuple = bucket[i];
// 找到删除此数据
if(tuple[0] === key){
bucket.splice(i,1);
// 存储数量-1
this.count--;
// 4.判断是否需要缩容
if(this.limit > 7 && this.count < this.limit * 0.25){
this.resize(this.getPrime(Math.floor(this.limit / 2)))
}
return tuple[1]
}
}
// 没找到返回null
return null
}
// 哈希表是否为空
HashTable.prototype.isEmpty = function(){
return this.count == 0
}
// 哈希表中存储元素的个数
HashTable.prototype.size = function(){
return this.count
}
// 哈希表扩容&缩容
HashTable.prototype.resize = function(newlimit){
// 1.用oldStorage承载之前的数据
let oldStorage = this.storage;
// 2.重置storage
this.storage = [];
this.limit = newlimit;
this.count = 0;
// 3.遍历 将之前的数据重新存储到新的storage中
for(var i = 0; i < oldStorage.length; i++){
let bucket = oldStorage[i];
if(bucket == null) continue;
for(var j = 0; j < bucket.length; j++){
let tuple = bucket[j];
this.put(tuple[0],tuple[1])
}
}
}
// 判断是否是质数
HashTable.prototype.isPrime = function(num){
let temp = parseInt(Math.sqrt(num));
for(var i = 2; i <= temp; i++){
if(num % i === 0){
return false
}
}
return true
}
// 获取质数
HashTable.prototype.getPrime = function(num){
while(!this.isPrime(num)){
num++
}
return num
}
}
// 测试
let hash = new HashTable();
hash.put('1',{name: 'lili',age:12})
hash.put('tom',{age:19,id:1234})
hash.put('mariy',{age:11,sex:'女'})
console.log(hash);
// console.log(hash.get('1'));
// console.log(hash.remove('1'));
// console.log(hash.get('1'));
// console.log(hash.isEmpty());
// console.log(hash.size());
// hash.put('a',11)
// hash.put('b',21)
// hash.put('c',31)
// hash.put('d',41)
// hash.put('e',51)
// console.log(hash);
// console.log(hash.size());