哈希表结构_哈希表的扩容
哈希表的扩容
1. 为什么要扩容
1. 扩容即是将哈希表的长度增加,通常是变为原来的两倍
2. 使用链地址法封装哈希表时, 填装因子(loaderFactor)会大于1, 理论上这种封装的哈希表时可以无限插入数据的
3. 但是但是随着数据量的增多,哈希表中的每个元素会变得越来越长, 这是效率会大大降低
4. 因此, 需要通过扩容来提高效率
2. 如何扩容
1. 扩容就是将哈希表的存储空间增加为原来的两倍
2. 此时,需要将所有数据项都进行修改(需要重新调用哈希函数,来获取新的位置)
3. 哈希表扩容是一个比较耗时的过程,但是功在当代, 利在千秋
3. 什么情况下扩容
常见的情况是在填装因子(loaderFactor) > 0.75是进行扩容
4. 扩容的代码实现
1. 拷贝之前封装的哈希表代码
2. 在哈希表中增加变容(resize)方法
5. 哈希表扩容的代码实现
function hashMap(){ // 哈希表的属性 this.storage = []; this.count = 0; this.limit = 8; // 封装哈希函数类 hashMap.prototype.hashFun = function(str, size = 7){ // 1. 定义hashCode变量 var hashCode = 0; // 2. 霍纳算法,计算hashCode的值 for(var i = 0; i < str.length; i++){ // 这里的常数值37是常用质数值 hashCode = 37 * hashCode + str.charCodeAt(i); } // 3. 取余操作 var index = hashCode % size; return index; } // a. 向哈希表中插入数据 hashMap.prototype.put = function(key, value){ // 1. 将要插入的键转换成哈希码 var index = this.hashFun(key, this.limit); // 2. 根据索引值,取出storage中对应的bucket var bucket = this.storage[index]; // 3. 若取出的bucket为空 if(bucket == undefined){ // 为空,则创建一个数组,并将新增的数据以数组的形式存入数组 bucket= [[key, value]]; this.storage[index] = bucket; return true; } // 4 若取出的bucket为重复数据, 则修改value值,并返回true; for(var i = 0; i < bucket.length; i++){ if(bucket[i][0] == key){ bucket[i][1] = value; return true; } } // 5. 若不为重复数据,则添加key和value,并返回true; bucket.push([key, value]); this.count += 1; return true // 6. 判断是否需要扩容 } // b. 在哈希表中查找数据 hashMap.prototype.get = function(key){ // 首先计算输入key值的哈希码 var index = this.hashFun(key, this.limit); // 取出哈希码对应的那个bucket var bucket = this.storage[index]; if(bucket == undefined){ return null; } // 依次遍历这个bucket for(var k = 0; k < bucket.length; k++){ if(bucket[k][0] == key){ return bucket[k][1]; } } // 若没有找到这个key值,返回null return null; } // c. 从哈希表中删除元素 hashMap.prototype.remove = function(key){ // 首先计算输入key值的哈希码 var index = this.hashFun(key, this.limit); // 根据哈希码.取出对应的bucket var bucket = this.storage[index]; // 依次查找bucket中的元素 for(var i =0; i < bucket.length; i++){ if(bucket[i][0] == key){ bucket.splice(i, 1); this.count -=1; return true; } } return false; } // d. 判断哈希表是否为空 hashMap.prototype.isEmpet = function(){ return count == 0; } // e. 查看哈希表中的数据个数 hashMap.prototype.size = function(){ return this.count; } // f. 统计哈希表中存储的数据的分布情况 hashMap.prototype.sta = function(){ var sta = []; for(var s = 0; s < this.storage.length; s++){ if(this.storage[s] == undefined){ sta.push(0); }else{ sta.push(this.storage[s].length); } } return sta } // g. 扩/缩容方法 hashMap.prototype.resize = function(newLimit){ // 1. 首先保存已保存在原哈希表中的数据 var oldStorage = this.storage; // 2. 新哈希表的方法 this.storage = []; this.count = 0; this.limit = newLimit; // 3. 扩容/缩容操作 for(var j = 0; j < oldStorage.length; j++){ // 1. 取出原哈希表的每个元素链 var bucket = oldStorage[j]; for(var k = 0; k < bucket.length; k++){ // 2. 取出每个元素链内的元素 即每组数据为: key = bucket[k][0], value = bucket[k][1] var index = this.hashFun(bucket[k][0], this.limit); // 3. 将元素依次放入新的哈希表中 // 3.1 判断新哈希表中的元素链是否为空 if(this.storage[index] == undefined){ // 为空,则直接放入 this.storage[index] = [bucket[k]]; break; }else{ // 不为空,则添加在末尾 this.storage[index].push(bucket[k]); } // 3. 将元素依次放入新的哈希表中 // 这一步也可以调用自身的put方法 // this.put(bucket[k][0], bucket[k][1]); } } } }