📅  最后修改于: 2023-12-03 15:07:06.160000             🧑  作者: Mango
哈希表是一种常用的数据结构,能够提供高效的查找、插入和删除操作。但是,当哈希表中的元素数目增加到一定程度时,冲突将会愈发频繁,使得哈希表的性能下降。为了解决这个问题,我们可以采用链地址法,即在哈希表中存储链表,来处理哈希表冲突。而双链表则是链表的一种,可以方便地从前往后以及从后往前遍历元素。因此,具有双链表的哈希表链接能够提供高效的哈希表操作,并且可以灵活地支持双向遍历。
下面是一个具有双链表的哈希表链接的示例代码:
template <typename KeyType, typename ValueType>
class HashTable {
private:
static const int TABLE_SIZE = 997;
struct HashNode {
KeyType key;
ValueType value;
HashNode *prev;
HashNode *next;
HashNode(const KeyType &k, const ValueType &v) : key(k), value(v), prev(nullptr), next(nullptr) {}
};
vector<HashNode *> table;
public:
HashTable() {
table.assign(TABLE_SIZE, nullptr);
}
~HashTable() {
clear();
}
void clear() {
for (int i = 0; i < TABLE_SIZE; ++i) {
HashNode *cur = table[i];
while (cur) {
HashNode *temp = cur;
cur = cur->next;
delete temp;
}
table[i] = nullptr;
}
}
void put(const KeyType &key, const ValueType &value) {
int pos = hashFunc(key);
HashNode *cur = table[pos];
while (cur) {
if (cur->key == key) {
cur->value = value;
return;
}
cur = cur->next;
}
HashNode *node = new HashNode(key, value);
if (table[pos]) {
node->next = table[pos];
table[pos]->prev = node;
}
table[pos] = node;
}
bool remove(const KeyType &key) {
int pos = hashFunc(key);
HashNode *cur = table[pos];
while (cur) {
if (cur->key == key) {
if (cur->prev) {
cur->prev->next = cur->next;
}
if (cur->next) {
cur->next->prev = cur->prev;
}
if (table[pos] == cur) {
table[pos] = cur->next;
}
delete cur;
return true;
}
cur = cur->next;
}
return false;
}
bool contains(const KeyType &key) const {
int pos = hashFunc(key);
HashNode *cur = table[pos];
while (cur) {
if (cur->key == key) {
return true;
}
cur = cur->next;
}
return false;
}
ValueType get(const KeyType &key) const {
int pos = hashFunc(key);
HashNode *cur = table[pos];
while (cur) {
if (cur->key == key) {
return cur->value;
}
cur = cur->next;
}
return ValueType();
}
private:
int hashFunc(const KeyType &key) const {
// 哈希函数的实现
int hashValue = 0;
for (char c : key) {
hashValue = (hashValue * 31 + c) % TABLE_SIZE;
}
return hashValue;
}
};
这个哈希表使用了双指针,保存了每个节点的前驱和后继,实现了基本的哈希表操作:插入、删除、查找和获取元素值。当插入时,如果散列到的位置已经存在元素,则将新元素插入到链表头部;当删除时,需要考虑当前节点的前驱和后继节点的关系,以及对头节点的处理;当查找或获取元素值时,需要遍历对应链表查找。由于哈希表中每个节点只会在链表中出现一次,因此元素查找和删除的时间复杂度都是 O(1),即使是在冲突频繁的情况下,哈希表的性能也能够得到保证。
使用这个具有双链表的哈希表链接非常简单,只需要在程序中包含上述代码,然后按照如下方式调用即可:
HashTable<string, int> table;
table.put("apple", 1);
table.put("banana", 2);
table.remove("banana");
cout << table.contains("apple") << endl;
cout << table.get("apple") << endl;
这个哈希表可以接受任意类型的键和值,只需要保证它们支持相等比较运算符(==)和哈希函数即可。使用 put
方法向哈希表中插入元素,使用 remove
方法删除元素,使用 contains
方法查找元素是否存在,使用 get
方法获取元素的值。除此之外,这个哈希表还提供了 clear
方法,可以清空哈希表中的所有元素。