哈希表定义
- 是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表, 也就是哈希表.
自定义哈希表的代码实现
// 根据链地址法实现哈希表
function HashTable(){
// 属性
this.storage = [];
this.count = 0;
this.limit = 7;
// 哈希函数
HashTable.prototype.hashFunc = function(str, size){
// 1.定义hashcode变量
let hashCode = 0;
// 2.使用霍纳算法计算hashcode
for (let i = 0; i < str.length; i++) {
hashCode = 37 * hashCode + str.charCodeAt(i);
}
// 3. 取余操作
let index = hashCode % size;
return index;
}
// 插入&修改的操作
HashTable.prototype.put = function(key, value){
/*
1.根据key获取索引值,将数据插入到对应的位置。
2.根据索引值取出bucket
1)如果桶不存在,就创建一个bucket放在索引所在的位置
3.判断新增还是修改原来的值
1)如果在桶中已经存在该元素,就替换它的值
2)如果不存在,就直接添加到桶中。
4.新增操作
*/
// 1.获取对应key的index
let index = this.hashFunc(key, this.limit);
// 2.根据对应的index获取桶
let bucket = this.storage[index];
if(bucket == null){
bucket = [];
this.storage[index] = bucket;
}
// 3.判断是替换还是新增
for (let i = 0; i < bucket.length; i++) {
const tuple = bucket[i];
if (tuple[0] == key){
tuple[1] = value;
return
}
}
// 4.如果没有找到,就是新增
bucket.push([key, value]);
this.count += 1;
// 5. 判断是否要进行扩容 装载因子如果大于0.75,就需要对数组进行扩容
if (this.count > this.limit * 0.75) {
let tempLimit = this.limit * 2;
let newLimit = this.getPrime(tempLimit); //转换为质数
this.resize(newLimit);
}
}
// 查询
HashTable.prototype.get = function(key){
// 1. 通过key获取对应的index
let index = this.hashFunc(key, this.limit);
// 2. 根据对应的index获取该位置的桶 bucket
let bucket = this.storage[index];
// 3.如果桶不存在,那么该元素肯定也不存在,直接返回null
if(bucket == null){
return null;
}
// 4.如果桶存在,就遍历找到和key对应的数组
for (let i = 0; i < bucket.length; i++) {
const tuple = bucket[i];
if (tuple[0] == key) {
return tuple[1];
}
}
// 5.说明桶中没有找到,说明不存在,直接返回null
return null;
}
// 删除元素
HashTable.prototype.delete = function(key){
// 1.获取key对应的index
let index = this.hashFunc(key, this.limit);
// 2.获取该index的bucket
let bucket = this.storage[index];
// 3.判断bucket是否存在
if(bucket == null) return null;
// 4.找到当前key所在的桶中的位置
for (let i = 0; i < bucket.length; i++) {
const tuple = bucket[i];
if (tuple[0] == key) {
bucket.splice(i, 1);
this.count--;
// 5. 判断是否需要缩小容量
if (this.limit > 7 && this.count / this.limit * 0.25) {
let tempLimit = Math.floor(this.limit / 2);
let newLimit = this.getPrime(tempLimit);
this.resize(newLimit);
}
return tuple[1];
}
}
// 5.说明没有找到
return null;
}
// Hash表是否为空
HashTable.prototype.isEmpty = function(){
return this.count == 0;
}
// Hash表的长度
HashTable.prototype.size = function(){
return this.count;
}
// hash表的扩容或者缩容
HashTable.prototype.resize = function(newLimit){
// 1.保存原有的hash表
let oldStorage = this.storage;
// 2.重置一些属性
this.storage = [];
this.count = 0;
this.limit = newLimit;
for (let i = 0; i < oldStorage.length; i++) {
const bucket = storage[i];
if (bucket) {
for (let j = 0; j < bucket.length; j++) {
const tuple = bucket[j];
this.put(tuple[0], tuple[1]);
}
}
}
}
// 判断某个值是否是质数
HashTable.prototype.isPrime = function(num){
// 1.获取num的平方根, 如果某一个数字能分解因子,那么它能拆成的因子一个比她的平方根小,
// 另一个比平方根大,所以我们只要比对到平方根的位置,就能判断是否能整除
let temp = parseInt(Math.sqrt(num));
for (let index = 2; index < temp; index++) {
if (num % index === 0) {
return false
}
}
return true;
}
// 获取质数的方法
HashTable.prototype.getPrime = function(num){
while (!this.isPrime(num)) {
// 如果num不是质数,然后就+1,然后再判断,一直找到是质数为止,然后跳出循环,直接返回
num++;
}
return num
}
}
哈希表的应用
-
题目:两数之和
-
给定一个整数数组
nums和一个整数目标值target,请你在该数组中找出 和为目标值target的那 两个 整数,并返回它们的数组下标。 -
代码实现
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
let map = new Map();
for(let i = 0; i <= nums.length - 1; i++){
let value = nums[i];
let different = target - value;
if(map.has(different)){
return [map.get(different), i];
}else{
map.set(value, i);
}
}
};