我正在学习哈希表,试图了解它们的工作原理。我想用一个单独的链接(使用数组中的列表)制作一个相当简单的哈希表。我有几个问题:
假设密钥可以是任何类型,我会要求用户实现散列函数,对吧?这可以避免吗?
用户还需要在初始化时提供包含列表(用于冲突)的数组的长度,对吗?这可以避免吗?
如果您有任何其他提示,或者在哈希表的C ++中有一些明确的代码示例,我将非常感激。
感谢您的帮助。
答案 0 :(得分:5)
通常,是的,您需要客户端指定哈希函数,因为如果您正在编写通用哈希表并且在任意类型T上运行,您将无法知道如何以某种方式对其进行哈希处理语义上有意义。您可以通过在存储的元素类型和散列函数上参数化类来完成此操作。例如:
template <typename T, typename Hash = std::hash<T>>
class MyHashTable {
/* ... */
}
在这里,您可以使用带模板的默认参数来选择默认的哈希函数,除非用户另有指定。
虽然客户端通常可以指定表的初始大小,但这不是必需的。您可以对桶的数量进行有根据的猜测(比如说,最初使用17个桶),随着负载因子的增加而增加表。这类似于std::vector
的工作原理:实现可以选择默认大小,但如果客户端明确要求预定义向量或调用reserve
,则实现将从用户获取提示。例如,您可以使用
template <typename T, typename Hash = std::hash<T>>
class MyHashTable {
public:
MyHashTable(unsigned numBuckets = 17);
}
这样,客户端就可以构造一个具有默认桶数的哈希表,或者如果他们对桶的数量有所了解,他们可以将其指定为参数。但是,您可能还希望将桶隐藏为详细信息,并让客户端指定它们期望放入表中的元素数量,然后让您的类在此后面进行计算。这样可以更容易地在幕后切换实现,因此如果您想使用类似动态完美哈希表而不是链接哈希表的类,那么该类可以处理计算初始大小的复杂性。
至于代码示例,我不确定如何在不消除构建哈希表所涉及的大量复杂性的情况下提供任何代码示例。 :-)如果您感兴趣的是一段特定的代码并且无法自行编写,请随意将其作为单独的问题发布,以便您可以获得更有针对性的反馈。
希望这有帮助!
答案 1 :(得分:0)
查看散列算法的各种实现。有很多可用的。如果需要,您可以将哈希存储设置为可变。它取决于你。使用大多数哈希算法,可以进行冲突。记住这一点。
答案 2 :(得分:0)
如果您正在尝试了解哈希表,我建议您从最简单的哈希表开始,这是线性链表哈希表
在这里你考虑一个固定大小的指针数组(指向你定义的类型项的指针),你的项目将存储在哪里,考虑还有一些计数器,一个用于跟踪数组的长度,另一个用于跟踪在某个时刻之前添加到表中的项目数量
您可以使用宏来定义将项添加到哈希表中的功能,如此
h(k) = k % M
其中k是要添加的项的索引(键),M是素数,表示指针数组的大小(例如13,29,41,543)和h(k)将为您提供将要插入项目的位置。
你应该考虑使用固定大小的指针数组的原因是因为这样你有
O(n)
成本。
因此,从这个简单的函数开始,您可以修改它并考虑实现一些更复杂的函数,如开放地址,线性探测,二次探测和双重散列
至于用户请求的关于项目数量的输入我完全同意先前所说的templatetypedef