c++ - HashMap 直接访问运算符 []

标签 c++ c++11 stl hashtable unordered-map

我已经实现了一个哈希表(std::unordered_map):

#include <bits/stdc++.h>
#ifndef HASH_TABLE_H
#define HASH_TABLE_H

#define TABLE_SIZE 100

// Hash node class template
template <typename K, typename V>
class HashNode {
public:
    HashNode(const K &key, const V &value)
        : key(key)
        , value(value)
        , next(NULL) {
    }

    K getKey() const {
        return key;
    }

    V getValue() const {
        return value;
    }

    void setValue(V value) {
        HashNode::value = value;
    }

    HashNode *getNext() const {
        return next;
    }

    void setNext(HashNode *next) {
        HashNode::next = next;
    }
private:
    // key-value pair
    K key;
    V value;
    // next bucket with the same key
    HashNode *next;
};

// Default hash function class
template <typename K>
struct KeyHash {
    unsigned long operator()(const K& key) const {
        return reinterpret_cast<unsigned long>(key) % TABLE_SIZE;
    }
};

// Hash map class template
template <typename K, typename V, typename F = KeyHash<K>>
class HashTable {
public:
    HashTable() {
        // construct zero initialized hash table of size
        table = new HashNode<K, V> *[TABLE_SIZE]();
    }

    ~HashTable() {
        // destroy all buckets one by one
        for (int i = 0; i < TABLE_SIZE; ++i) {
            HashNode<K, V> *entry = table[i];
            while (entry != NULL) {
                HashNode<K, V> *prev = entry;
                entry = entry->getNext();
                delete prev;
            }
            table[i] = NULL;
        }
        // destroy the hash table
        delete [] table;
    }

    bool get(const K &key, V &value) {
        unsigned long hashValue = hashFunc(key);
        HashNode<K, V> *entry = table[hashValue];
        while (entry != NULL) {
            if (entry->getKey() == key) {
                value = entry->getValue();
                return true;
            }
            entry = entry->getNext();
        }
        return false;
    }

    void put(const K &key, const V &value) {
        unsigned long hashValue = hashFunc(key);
        HashNode<K, V> *prev = nullptr;
        HashNode<K, V> *entry = table[hashValue];
        while (entry != nullptr and entry->getKey() != key) {
            prev = entry;
            entry = entry->getNext();
        }
        if (entry == nullptr) {
            entry = new HashNode<K, V>(key, value);
            if (prev == nullptr) {
                // insert as first bucket
                table[hashValue] = entry;
            } else {
                prev->setNext(entry);
            }
        } else {
            // just update the value
            entry->setValue(value);
        }
    }

    // direct access operator overloading 
    V& operator [] (const K& key) {
        V value;
        get(key, value);
        return value;
    }

    void remove(const K &key) {
        unsigned long hashValue = hashFunc(key);
        HashNode<K, V> *prev = nullptr;
        HashNode<K, V> *entry = table[hashValue];
        while (entry != nullptr and entry->getKey() != key) {
            prev = entry;
            entry = entry->getNext();
        }
        if (entry != nullptr) {
            if (prev == nullptr) {
                // remove first bucket of the list
                table[hashValue] = entry->getNext();
            } else {
                prev->setNext(entry->getNext());
            }
            delete entry;
        }
    }

private:
    // hash table
    HashNode<K, V> **table;
    F hashFunc;
};

#endif // HASH_TABLE_H

struct MyKeyHash {
    unsigned long operator()(const int& k) const {
        return k % 10;
    }
};

int main(void) {
    HashTable<int, std::string, MyKeyHash> hmap;
    hmap.put(1, "val1");
    hmap.put(2, "val2");
    hmap.put(3, "val3");
    std::string value;
//    hmap.get(2, value);
    std::cout << hmap[2] << std::endl; // val2
//    hmap[2] = "val_new";
//    std::cout << hmap[2] << std::endl; // val2
    bool res = hmap.get(3, value);
    if (res)
        std::cout << value << std::endl; // val3
    hmap.remove(3);
    res = hmap.get(3, value);
    if (res)
        std::cout << value << std::endl; // nothing
    return 0;
}

问题是直接访问运算符 [] 重载无法正常工作。我可以通过 hmap[1] 访问一个键,因为函数签名是 V& operator [] (const K& key) 但我不能像 hmap[ 1] = "something" 因为它不返回任何值将被覆盖的指针。我怎样才能实现这两个功能?

最佳答案

改变:

V& operator [] (const K& key) {
    V value;
    get(key, value);
    return value;
}

进入:

V& operator [] (const K& key) {
    unsigned long hashValue = hashFunc(key);
    HashNode<K, V> *entry = table[hashValue];
    while (entry != NULL) {
        if (entry->getKey() == key) {
            return entry->getValue();
        }
        entry = entry->getNext();
    }
    // alternatively, as suggested by NetVipeC, you can return
    // here a reference to default-constructed element under given key
    // e.g.: put(key, V{}); return (*this)[key]; 
    throw std::range_error{"Key not found!"};
}

并使 HashNode::getValue 也返回引用:

V& getValue() {
    return value;
}

const V& getValue() const {
    return value;
}

关于c++ - HashMap 直接访问运算符 [],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25584065/

相关文章:

python - Windows中的Simstring(python)安装

c++ - unordered_map,为什么有些桶有超过 1 个元素甚至散列值都不同?

c++ - constexpr 的推导类型是什么?

c++ - 如果我们不想将每个元素转换为一个转换元素,而是两个,我们如何使用 std::transform?

c++ - 编译器如何区分 "vector::insert"的两个变体?

C++删除对象,它会锁定吗?

c++ - 找不到 Gurobi 库

c++ - 如何使用 libcurl 和 POP3 删除电子邮件?

c++ - vector 的 emplace_back

c++ - 关于自动类型推导,哪一项是正确的?