发布时间:2024-12-28 19:01
哈希函数:将一个字符串转化成对应的下标的封装程序。
哈希表:据关键码值(Key value)而直接进行访问的数据结构。
哈细化:一个关键字将其转化成对应的数字,再将这个数据映射到对应的内存空间的范围,而这一映射的过程就是哈希化。
应用场景:
①如果在一个公司中,我想要根据一个人名,来查找这个人的全部信息如果按照直接查找,效率太低。而使用哈希表,可以将人名转化成对应的下标,根据下标来查找,可以提高效率。
②、可以应用在字典的查找与搜索过程中。
步骤一:
先将对应的字符根据对应的编码转化成数字。
步骤二:
因为步骤一得到的数字太大,所以可以进行哈希化,就是根据一个操作将其转化成给定范围的地址。
步骤三:
如果出现冲突的情况,可以有两种操作的:一:开放地址法,二:链地址法,接下来的操作我们会使用链地址法进行相关的操作。
链地址法“:
上面的图就是链地址法的相关操作,将地址重复的数据全部在用指针指向一个数组。
代码操作
这里我们将哈希表封装成一个构造函数
需要的数据:①整个哈希表全部数据
②哈希表中限制长度
③哈希表中的元素数量
需要的方法:
①放入元素
②获取元素
③修改元素
④删除元素
⑤判断是否为空
⑥输出元素个数
⑦扩展空间
<script>
function hashTable() {
this.storage = [];
this.limit = 7;
this.count = 0;
hashTable.prototype.hashFunc = function (str, size) {
let hashCode = 0;
for (let i = 0; i < str.length; i++) {
hashCode = hashCode * 37 + str.charCodeAt(i);
}
let hash = hashCode % size;
return hash;
}
// 添加、更改哈希函数中的值
hashTable.prototype.push = function (key, value) {
// 先用哈希函数将其转化
let index = this.hashFunc(key, this.limit);
let bucket = this.storage[index];
if (bucket == null) {
bucket = [];
this.storage[index] = bucket;
}
for (let i = 0; i < bucket.length; i++) {
if (key == bucket[i][0]) {
bucket[i][1] = value;
return;
}
}
// 指向到这里就不存在,则直接插入
bucket.push([key, value]);
this.count++;
if (this.count >= this.limit * 0.75) {
this.limit = this.getPrime(this.limit * 2);
this.resize(this.limit);
}
}
// 获取操作
hashTable.prototype.get = function (key) {
let index = this.hashFunc(key, this.limit);
let bucket = this.storage[index];
if (bucket == null) {
return null;
}
for (let i = 0; i < bucket.length; i++) {
if (key == bucket[i][0]) {
return bucket[i][1];
}
}
// 执行到这里说明不存在该值
return null;
}
// 删除方法
hashTable.prototype.remove = function (key) {
let index = this.hashFunc(key, this.limit);
let bucket = this.storage[index];
if (bucket == null) {
return null;
}
for (let i = 0; i < bucket.length; i++) {
if (key == bucket[i][0]) {
this.count--;
if (this.limit <= 7 && this.count <= this.limit * 0.25) {
this.limit = this.getPrime(this.limit);
this.resize(this.limit);
}
return bucket[i][1];
}
}
return null;
}
// 判断是否哈希表是否为空
hashTable.prototype.isEmpty = function () {
return this.count == 0;
}
// 输出哈希表的长度
hashTable.prototype.size = function () {
return this.count;
}
// 判断是否为质数
hashTable.prototype.isPrime = function (num) {
let sqrt = Math.sqrt(num);
for (let i = 2; i <= sqrt; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
// 获取一个质数
hashTable.prototype.getPrime = function (num) {
while (!this.isPrime(num)) {
num++;
}
return num;
}
// 设置扩容,缩容操作
hashTable.prototype.resize = function (newList) {
// 重新定义变量
let oldStorage = this.storage;
this.storage = [];
this.count = 0;
this.limit = newList;
for (let i = 0; i < oldStorage.length; i++) {
let busket = oldStorage[i];
if (busket == null) {
continue;
}
for (let j = 0; j < busket.length; j++) {
var tuple = busket[j];
this.push(tuple[0],tuple[1]);
}
}
}
}
let hs = new hashTable();
hs.push(\"dl\", \'201902091\');
hs.push(\"xsy\", \"201902018\");
console.log(hs);
hs.push(\"zcc\", \'201902091\');
hs.push(\"bjr\", \"201902018\");
hs.push(\"fzl\", \'201902091\');
hs.push(\"hst\", \"201902018\");
console.log(hs);
script>
解析:上面是完整的代码,其中包含扩容和缩容的操作,原因是:在哈希表中,如果在多余的元素中,使用链地址法,则可以存放无数个元素,当元素的个数多的时候,查找时,消耗的时间以及其效率都会增多。所以当满足某一个条件时,执行扩容操作。当满足某一个条件时,进行缩容操作,因为当元素个数较少时,如果容积比较大,比较浪费内存空间。
并且在上面代码中,增加了查找质数的函数,因为当哈希表的空间范围是质数的时候,元素分布比较均匀。