在 C 中实现 HashMap [关闭]
Posted
技术标签:
【中文标题】在 C 中实现 HashMap [关闭]【英文标题】:Implementing a HashMap in C [closed] 【发布时间】:2010-10-24 17:11:08 【问题描述】:如何像 C++ STL 中那样从头开始在 C 中创建 Hashmap?
将考虑哪些参数以及如何测试哈希图?例如,在您可以说您的哈希图已完成之前,您将运行的基准测试用例是什么?
【问题讨论】:
【参考方案1】:好吧,如果您了解它们背后的基础知识,那应该不会太难。
通常您创建一个名为“buckets”的数组,其中包含键和值,以及用于创建链表的可选指针。
当您使用键访问哈希表时,您使用自定义哈希函数处理该键,该函数将返回一个整数。然后你取结果的模数,这就是你的数组索引或“桶”的位置。然后你用存储的密钥检查未散列的密钥,如果匹配,那么你找到了正确的位置。
否则,您遇到了“冲突”,必须爬过链表并比较键,直到匹配为止。 (注意一些实现使用二叉树而不是链表来解决冲突)。
查看这个快速哈希表实现:
https://attractivechaos.wordpress.com/2009/09/29/khash-h/
【讨论】:
除了 LL 和树之外,您还可以为每个存储桶创建一个哈希映射,该映射使用不同的哈希来处理冲突。【参考方案2】:最佳方法取决于预期的密钥分布和数量 的碰撞。如果预计碰撞相对较少,那真的 使用哪种方法无关紧要。如果有很多碰撞 预期,那么使用哪个取决于重新散列的成本或 探测与操作可扩展的存储桶数据结构。
但这里是An Hashmap Implementation in C的源代码示例
【讨论】:
正如后面的帖子所说,我们还需要处理碰撞。此外,哈希实现有一个固定的 table_size。如果我们想动态增加 hashmap 的大小,而程序员不知道它是如何完成的。你能推荐点什么吗? 调整键空间的大小意味着更改散列函数或至少更改函数的参数并重新散列所有条目。每个不同大小的映射都需要一组不同的哈希函数来维护所需的密钥分布。 链接的代码是学生写的。 “这是我用 C 语言编写的第一个数据结构”。出于某种原因,他添加了同步代码以使其成为线程安全的。【参考方案3】:hashmap 的主要目标是存储数据集并使用唯一键提供近乎恒定的时间查找。有两种常见的 hashmap 实现方式:
分离链:一个带有一组桶(链表) 开放式寻址:分配有额外空间的单个数组,因此可以通过将条目放在相邻插槽中来解决索引冲突。如果哈希映射的哈希函数可能很差,不希望为可能未使用的插槽预先分配存储空间,或者条目可能具有可变大小,则最好使用单独的链接。即使负载因子超过 1.0,这种类型的 hashmap 也可以继续相对有效地运行。显然,每个条目都需要额外的内存来存储链表指针。
当负载因子保持在某个阈值以下(通常约为 0.7)并使用相当好的哈希函数时,使用开放寻址的哈希图具有潜在的性能优势。这是因为它们避免了潜在的缓存未命中和与链表相关的许多小内存分配,并在一个连续的、预先分配的数组中执行所有操作。迭代所有元素也更便宜。问题是使用开放寻址的哈希图必须重新分配到更大的大小并重新哈希以保持理想的负载因子,否则它们将面临显着的性能损失。它们的负载系数不可能超过 1.0。
创建哈希图时要评估的一些关键性能指标包括:
最大负载率 插入时的平均冲突计数 冲突分布:不均匀分布(聚类)可能表明哈希函数不佳。 各种操作的相对时间:放置、获取、删除现有和不存在的条目。这是我制作的一个灵活的 hashmap 实现。我使用开放寻址和线性探测来解决冲突。
https://github.com/DavidLeeds/hashmap
【讨论】:
【参考方案4】:除了简单的溢出条目链接列表之外,还有其他机制可以处理溢出,例如浪费很多内存。
使用哪种机制取决于您是否可以选择散列函数并可能选择多个(以实现例如双散列来处理冲突);如果您希望经常添加项目,或者地图在填充后是静态的;您是否打算删除项目; ...
实现这一点的最佳方法是首先考虑所有这些参数,然后不要自己编写代码,而是选择成熟的现有实现。谷歌有一些很好的实现——例如http://code.google.com/p/google-sparsehash/
【讨论】:
虽然与算法相关,但 sparsehash 是哈希图的 C++ 实现。如果您正在寻找纯 C 预卷哈希图,请查看其他地方。以上是关于在 C 中实现 HashMap [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
PHP 警告:count():参数必须是在 C:\\htdocs\my.php 中实现 Countable 的数组或对象 [关闭]