【发布时间】:2017-05-11 14:47:45
【问题描述】:
我正在构建一个 C++ 开放寻址哈希表。它由一个数组组成:
struct KeyValue {
K key;
V value;
}
Key 类型有两个特殊元素:空和墓碑。第一个用来说明slot是空闲的,第二个用来说明slot已经被使用过但后来又被删除了(探测需要)。
主要的挑战是为此结构设计一个高效的 API。我想最小化一个键被散列和寻找一个槽的次数。
到目前为止,我发现以下 API 不安全:
// Return the slot index if the key is in the table
// or a slot index where I can construct the KeyValue
// if the key is not here (or -1 if there is no slot
// available and the insertion of such a key would
// need to grow the hash table)
int search(const K& key)
// Tells if the slot is empy (or if i == -1)
bool empty(int i)
// Construct a KeyValue in the HashTable in the slot i
// which has been found by search. The i might be changed
// if the table needs to grow.
void insert(const K& key, const V& value, int& i)
// Accessors for a slot i which is occupied
const V& value(int i);
注意,表格也有经典的功能如
void insert(const K& key, const V& value)
它计算哈希,搜索一个槽,并将对插入到表中。但我想在这里集中讨论允许程序员非常有效地使用表格的界面。
例如,这里有一个函数,如果 f(key) 从未计算过,则返回它的值;如果 f(key) 已经计算过,则返回其值。
const V& compute(const K& key, HashTable<K, V>& table) {
int i = table.search(key);
if (table.empty(i)) {
table.insert(key, f(key), i);
}
return table.value(i);
}
我并不完全热衷于这个 HashTable 的接口,因为方法 insert(const K&, const V&, int&) 对我来说真的很不安全。
您对更好的 API 有什么建议吗?
PS:Chandler Carruth 的演讲“算法的性能,数据结构的效率”,特别是在 23:50 之后,非常好理解 std::unordered_map 的问题
【问题讨论】:
-
你的目标是什么?表现?内存使用情况?无论如何,您能详细说明为什么
std::unordered_map不够用吗? -
我们的目标是得到一个高性能的HashTable。 std::unordered_map 的问题之一是解决了与链表的冲突,这从性能角度来看是不利的。另外,尝试使用 std::unordered_map 编写“计算”。
-
知道了。我也很困惑为什么要将“插槽索引”公开给插入的调用者。因为哈希表的全部意义在于您可以通过“key”插入一些东西,然后通过“key”查找它。如果您要向调用者返回一个槽索引以供后续查找,那么您的实现也可能只是一个带有增量索引的平面数组。但我认为您真正想要的只是公开三种方法:
void Insert(k,v)、void Remove(k)和v Lookup(k)。 -
另外,几年前我编写了自己的哈希表类,目标是在实例构建后不再分配内存。因为在服务器端,内存分配会损害性能。欢迎您参考或使用。 It's here on GitHub 与 unit tests
-
selbie:如果你想编写一个只对密钥进行一次哈希处理的“计算”函数,则需要返回 i。显然,哈希表的常规用法是稍后请求值并通过哈希函数完成。感谢您在 github 上的参考。
标签: c++ api hash hashtable unordered-map