散列(或哈希)是一种数据结构,允许我们按键存储和检索值。JavaScript中的对象实际上就是哈希表,但为了教学目的,我们将从头开始实现一个简单的哈希表。
以下是一个简单的哈希表实现,以及一些常见操作的详细说明:
class HashTable {
constructor(size = 50) {
// 初始化一个固定大小的数组来存储数据。
this.buckets = Array(size);
for (let i = 0; i < this.buckets.length; i++) {
this.buckets[i] = new LinkedList();
}
this.size = size;
}
// 使用简单的哈希函数将键转换为数组索引。
hash(key) {
let hashValue = 0;
for (let char of key) {
hashValue += char.charCodeAt(0);
}
return hashValue % this.size;
}
/**
* 将键值对插入哈希表。
* @param {string} key - 要插入的键。
* @param {*} value - 要插入的值。
*/
insert(key, value) {
const index = this.hash(key);
this.buckets[index].append({key, value});
}
/**
* 从哈希表中按键检索值。
* @param {string} key - 要检索的键。
* @returns {*} 返回与键关联的值,如果找不到则返回 null。
*/
retrieve(key) {
const index = this.hash(key);
const bucketLinkedList = this.buckets[index];
const node = bucketLinkedList.find({ callback: (nodeValue) => nodeValue.key === key });
return node ? node.value.value : null;
}
/**
* 从哈希表中删除键值对。
* @param {string} key - 要删除的键。
*/
remove(key) {
const index = this.hash(key);
const bucketLinkedList = this.buckets[index];
const node = bucketLinkedList.find({ callback: (nodeValue) => nodeValue.key === key });
if (node) {
bucketLinkedList.delete(node.value);
}
}
}
class LinkedListNode {
constructor(value, next = null) {
this.value = value;
this.next = next;
}
}
class LinkedList {
constructor() {
this.head = null;
this.tail = null;
}
append(value) {
const newNode = new LinkedListNode(value);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
return this;
}
this.tail.next = newNode;
this.tail = newNode;
return this;
}
find({ value = undefined, callback = undefined }) {
if (!this.head) {
return null;
}
let currentNode = this.head;
while (currentNode) {
if (callback && callback(currentNode.value)) {
return currentNode;
}
if (value !== undefined && currentNode.value === value) {
return currentNode;
}
currentNode = currentNode.next;
}
return null;
}
delete(value) {
if (!this.head) {
return null;
}
let deletedNode = null;
while (this.head && this.head.value === value) {
deletedNode = this.head;
this.head = this.head.next;
}
let currentNode = this.head;
if (currentNode !== null) {
while (currentNode.next) {
if (currentNode.next.value === value) {
deletedNode = currentNode.next;
currentNode.next = currentNode.next.next;
} else {
currentNode = currentNode.next;
}
}
}
if (this.tail.value === value) {
this.tail = currentNode;
}
return deletedNode;
}
}
使用示例
const hashTable = new HashTable();
hashTable.insert("name", "Alice");
hashTable.insert("age", 25);
console.log(hashTable.retrieve("name")); // 输出: Alice
console.log(hashTable.retrieve("age")); // 输出: 25
hashTable.remove("name");
console.log(hashTable.retrieve("name")); // 输出: null
以上代码首先定义了一个哈希表类,其中使用了一个简单的哈希函数将字符串键转换为索引。这是一个非常简单的哈希函数,仅用于示例目的,在实际应用中可能需要更复杂和高效的哈希函数。为了处理哈希冲突,我们使用了链地址法,即每个桶存储一个链表。
然后,我们定义了一个链表节点类和一个链表类来支持哈希表的操作。
注意:这是一个简单的实现,仅用于教学目的。实际应用中的哈希表实现可能会更复杂,并包括更多的优化。