JavaScript数据结构——哈希表
JavaScript数据结构(哈希表)
哈希表
- 哈希表基于数组实现,但相对于数组。
- 提供非常快速的 插入-删除-查找 操作
- 哈希表中的
key
是不允许重复的,不能放置相同的key
,用于保存不同的元素
哈希化
:把字符串转化为对应的下标值。封装在一个函数中,这个函数就叫哈希函数
不同的字符串哈希化后可能等到同于个下标值,产生地址冲突。解决方案:链地址法和开放地址法
链地址法
:数组里边的位置,不再放的是但以的值,而可以是链表或者数组
开放地址法
:发现同一个下标上已经存在数据了,就将下标向后推一定步长,保存在还为空的位置。
- 线性探测:下标逐渐+1
- 二次探测:下标+1^2 、下标+ 2^2…
- 再哈希化:将字符串用另一个哈希函数,再次得到冲突后保存的地址。
装填因子
:总数据项 / 哈希表长度。一般当填装因子>0.75或者<
0.25时,查找效率会下降,此时要进行哈希表扩充或者压缩操作。
哈希表常见操作
put(key, value)
插入或修改操作。get(key)
获取哈希表中特定位置的元素。remove(key)
删除哈希表中特定位置的元素。isEmpty()
如果哈希表中不包含任何元素,返回trun
,如果哈希表长度大于 0 则返回false
。size()
返回哈希表包含的元素个数。resize(value)
对哈希表进行扩容操作。isPrime(value)
判断一个数是否为一个质数。getPrime(number)
得到离得number最近得质数.
JavaScript代码简单实现封装哈希表
采用链地址法,实现上面图片的结构
class Node {
constructor(key, value) {
this.key = key;
this.value = value;
this.next = null;
}
}
class HashTable {
constructor() {
this.storage = [];
this.length = 0;
this.limit = 7;
};
// 哈希函数的定义
HashFn(str, limit) {
let result = 0;
const prime = 11;
for (let item of str) {
result += result * prime + parseInt(item.charCodeAt());
}
return (result % limit)
}
//哈希查找和修改
put(key, value) {
const index = this.HashFn(key, this.limit);
if (!this.storage[index]) {
const node = new Node(key, value);
this.storage[index] = node;
this.length += 1;
// 判断填充因子 ,判断是否需要进行哈希表扩充
if (this.length > this.limit * 0.75) {
const num = this.getPrime(this.limit * 2);
this.resize(num)
}
return
}
const current = this.storage[index];
while (current.key != key) {
current = current.next;
if (!current) {
const node = new Node(key, value);
this.length += 1;
current = node;
return
}
};
// 查到
current.value = value;
return
}
get(key) {
const index = this.HashFn(key, this.limit);
if (!this.storage[index]) {
return null;
}
let current = this.storage[index];
while (current.key != key) {
current = current.next;
if (!current) {
return null
}
}
return current.value
}
remove(key) {
const index = this.HashFn(key, this.limit);
if (!this.storage[index]) {
return false
}
let current = this.storage[index];
if (!current.next && current.key == key) {
this.storage[index] = null;
this.length -= 1;
// 判断填充因子 ,判断是否需要进行哈希表压缩
if (this.length < this.limit * 0.25) {
const num = this.getPrime(this.limit / 2);
this.resize(num)
}
return current.value;
}
let prev = this.storage[index];
while (current.key != key) {
prev = current;
current = current.next;
if (!current) {
return false
}
}
const value = current.value;
prev.next = null;
this.length -= 1;
return value;
}
isEmpty() {
return this.length == 0;
}
size() {
return this.length;
}
// 得到离得number最近得质数
getPrime(number) {
while (!this.isPrime(number)) {
number++;
}
return number
}
// 判断是否是质数
isPrime(value) {
if (value <= 1 || value === 4) return false
const num = Math.ceil(Math.sqrt(value));
for (var i = 2; i < num; i++) {
if (num % i == 0) {
return false
}
}
return true
}
resize(value) {
const items = this.storage;
this.length = 0;
this.limit = value;
this.storage = [];
for (var i = 0; i < items.length; i++) {
const list = items[i];
if (!list) {
continue;
}
while (list) {
this.put(list.key, list.value);
list = list.next;
}
}
}
}
代码测试
const hashTable = new HashTable();
hashTable.put('aaa', { name: 'aaa', age: '18' });
hashTable.put('bbb', { name: 'bbb', age: '20' });
hashTable.put('ccc', { name: 'ccc', age: '21' });
hashTable.put('ddd', { name: 'ddd', age: '22' });
console.log(hashTable.get('bbb')); // { name: 'bbb', age: '20' }
console.log(hashTable.remove('ddd')); // { name: 'ddd', age: '22' }
console.log(hashTable.get('ddd')); // null
console.log(hashTable.get('ccc')); // { name: 'ccc', age: '21' }
'20' }
console.log(hashTable.remove('ddd')); // { name: 'ddd', age: '22' }
console.log(hashTable.get('ddd')); // null
console.log(hashTable.get('ccc')); // { name: 'ccc', age: '21' }