用C语言实现HashMap 如何在C++中从头开始创建哈希图,如C++ STL?< /P>

用C语言实现HashMap 如何在C++中从头开始创建哈希图,如C++ STL?< /P>,c,data-structures,hashmap,C,Data Structures,Hashmap,需要考虑哪些参数,如何测试hashmap?与中一样,在您可以说您的hashmap已经完成之前,您将运行哪些基准测试用例?最佳方法取决于预期的密钥分布和数量 碰撞的结果。如果预计会发生相对较少的碰撞,那么它真的会发生 使用哪种方法并不重要。如果有很多碰撞 预计,那么使用哪一种取决于再灰化或再灰化的成本 探测与操作可扩展bucket数据结构 但是这里有一个的源代码示例,如果您知道它们背后的基本知识,那么应该不会太难 通常,您创建一个名为“bucket”的数组,其中包含键和值,并带有一个可选指针来创建

需要考虑哪些参数,如何测试hashmap?与中一样,在您可以说您的hashmap已经完成之前,您将运行哪些基准测试用例?

最佳方法取决于预期的密钥分布和数量 碰撞的结果。如果预计会发生相对较少的碰撞,那么它真的会发生 使用哪种方法并不重要。如果有很多碰撞 预计,那么使用哪一种取决于再灰化或再灰化的成本 探测与操作可扩展bucket数据结构


但是这里有一个的源代码示例,如果您知道它们背后的基本知识,那么应该不会太难

通常,您创建一个名为“bucket”的数组,其中包含键和值,并带有一个可选指针来创建链接列表

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

否则,您将发生“冲突”,必须爬过链接列表并比较关键点,直到匹配为止。(注意,一些实现使用二叉树而不是链表进行冲突)

查看此快速哈希表实现:


除了简单的溢出项链表(例如浪费大量内存)之外,还有其他机制来处理溢出

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


实现这一点的最佳方法是首先考虑所有这些参数,然后不是自己编写代码,而是选择一个成熟的现有实现。Google有一些很好的实现——例如,hashmap的主要目标是存储一个数据集,并使用一个唯一的键提供几乎恒定的时间查询。hashmap实现有两种常见样式:

  • 单独链接:一个包含一组bucket(链表)的链接
  • 开放寻址:分配了额外空间的单个数组,因此可以通过将条目放置在相邻插槽中来解决索引冲突
如果hashmap可能具有较差的散列函数,不希望为潜在未使用的插槽预分配存储,或者条目可能具有可变大小,则最好使用单独的链接。即使负载因子超过1.0,这种类型的hashmap也可以相对有效地继续工作。显然,每个条目中都需要额外的内存来存储链表指针

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

创建hashmap时要评估的一些关键性能指标包括:

  • 最大负荷系数
  • 插入时的平均碰撞计数
  • 冲突分布:不均匀分布(群集)可能表示哈希函数不好
  • 各种操作的相对时间:放置、获取、删除现有和不存在的条目
下面是我制作的一个灵活的hashmap实现。我使用开放寻址和线性探测来解决冲突


正如后面的帖子所说,我们还需要处理碰撞问题。此外,哈希实现有一个类似于固定的表大小。如果我们想动态地增加hashmap的大小,而程序员不知道它是如何完成的。你能提出一些建议吗?调整密钥空间的大小意味着改变哈希函数或至少函数的参数,并重新设置所有条目的大小。每个不同大小的映射都需要一组不同的哈希函数来维护所需的密钥分布broken@JasonSturges:这里有一个archive.org链接:链接的代码是由一名学生编写的。“这是我用C写的第一个数据结构”。出于某种原因,他添加同步代码以使其成为线程安全的。而与算法相关的是,SabeSHASH是一个HASMAP的C++实现。如果您正在寻找pure-C预滚散列映射,请查看其他地方。除了LLs和树之外,每个bucket都可以有一个散列映射,它使用不同的散列来处理冲突。