📜  具有双链表的哈希表链接(1)

📅  最后修改于: 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 方法,可以清空哈希表中的所有元素。