实现HashMap

时间:2009-05-08 05:50:11

标签: c unit-testing hashmap

如何从头开始在C中创建Hashmap? 考虑什么参数以及如何测试hashmap有多好?与在您说哈希映射完成之前需要运行的基准测试用例一样。

4 个答案:

答案 0 :(得分:56)

如果你了解它们背​​后的基础知识,那就不应该太难了。

通常,您创建一个名为“buckets”的数组,其中包含键和值,以及一个用于创建链接列表的可选指针。

使用密钥访问哈希表时,使用自定义哈希函数处理密钥,该函数将返回整数。然后取结果的模数,即数组索引或“桶”的位置。然后使用存储的密钥检查未散列的密钥,如果匹配,则找到正确的位置。

否则,您遇到了“碰撞”,必须抓取链接列表并比较密钥,直到您匹配为止。 (注意一些实现使用二叉树而不是链表来进行冲突)。

查看这个快速哈希表实现:

http://attractivechaos.awardspace.com/khash.h.html

答案 1 :(得分:5)

最佳方法取决于预期的密钥分配和数量 碰撞如果预计会发生相对较少的碰撞,那就确实如此 使用哪种方法无关紧要。如果有很多碰撞 预期,然后使用哪个取决于重新散列的成本或 探测与操纵可扩展桶数据结构。

但这是An Hashmap Implementation in C

的源代码示例

答案 2 :(得分:3)

散列映射的主要目标是存储数据集,并使用唯一键在其上提供接近恒定时间的查找。有两种常见的hashmap实现样式:

  • 单独链接:一个带有一系列存储桶(链接列表)
  • 开放寻址:分配了额外空间的单个阵列,因此可以通过将条目放在相邻的插槽中来解决索引冲突。

如果散列映射可能具有较差的散列函数,则不希望单独链接,不希望为可能未使用的时隙预先分配存储,或者条目可能具有可变大小。即使当负载因子超过1.0时,这种类型的散列映射也可以继续相对有效地运行。显然,每个条目都需要额外的内存来存储链表指针。

当负载因子保持低于某个阈值(通常约为0.7)并且使用相当好的散列函数时,使用开放寻址的散列图具有潜在的性能优势。这是因为它们避免了潜在的高速缓存未命中以及与链表相关联的许多小内存分配,并在连续的预分配数组中执行所有操作。通过所有元素迭代也更便宜。捕获是使用开放寻址的哈希映射必须重新分配到更大的大小并重新分配以维持理想的负载因子,否则它们将面临显着的性能损失。它们的载荷系数不可能超过1.0。

创建散列映射时要评估的一些关键性能指标包括:

  • 最大负载系数
  • 插入时的平均碰撞次数
  • 碰撞的分布:不均匀分布(聚类)可能表示散列函数不佳。
  • 各种操作的相对时间:放置,获取,删除现有和不存在的条目。

这是我制作的灵活的hashmap实现。我使用开放寻址和线性探测来解决冲突。

https://github.com/DavidLeeds/hashmap

答案 3 :(得分:1)

还有其他机制来处理溢出,而不是简单的溢出条目的链接列表,例如,浪费了很多记忆。

使用哪种机制取决于你是否可以选择哈希函数并且可能选择多个(实现例如双哈希来处理冲突);如果您希望经常添加项目或者地图在填充后是静态的;如果你打算删除项目; ...

实现这一点的最佳方法是首先考虑所有这些参数,然后不自己编写代码,而是选择成熟的现有实现。谷歌有一些很好的实施 - 例如http://code.google.com/p/google-sparsehash/