【问题标题】:Chained Hash Table and understanding Deflate链式哈希表和理解 Deflate
【发布时间】:2011-07-26 14:14:22
【问题描述】:

我目前正在尝试在 C# 中创建自定义 Deflate 实现。

我目前正在尝试实现“模式搜索”部分,其中我拥有(最多)32k 数据,并且正在尝试为我的输入搜索最长的模式。

定义 Deflate 的 RFC 1951 说明了该过程:

压缩器使用链式哈希表来查找重复的字符串, 使用对 3 字节序列进行操作的哈希函数。在任何 压缩期间的给定点,让 XYZ 成为接下来的 3 个输入字节 进行检查(当然,不一定完全不同)。首先, 压缩器检查 XYZ 的哈希链。如果链是空的, 压缩器只是简单地将 X 写成一个字面字节并前进一个 输入中的字节。如果哈希链不为空,说明 序列 XYZ (或者,如果我们不走运,其他一些 3 个字节与 相同的哈希函数值)最近发生了,压缩机 将 XYZ 哈希链上的所有字符串与实际输入数据进行比较 从当前点开始的序列,并选择最长的 匹配。

我知道哈希函数是什么,也知道哈希表是什么。但是什么是“链式哈希表”?如何将这种结构设计为高效(在 C# 中)处理大量数据?不幸的是,我不明白 RFC 中描述的结构是如何工作的。

我可以选择什么样的哈希函数(什么是有意义的)?

提前谢谢你!

【问题讨论】:

  • 维基百科回答你的问题;无论如何,“chained”是用来描述哈希冲突解决策略的。 (哈希条目“指向”映射到它的键)
  • @lijie 好的,但我仍然不明白如何查找所有数据。考虑模式“A B B C A B B C A”,哈希表会是什么样子?前三个元素(分别是它们的哈希)“ABB”需要一个存储桶,但值是多少?只有 C 的哈希? BBC的哈希?以及插入新元素后丢弃第一个元素时的移位操作是如何进行的?
  • 呃...桶和密钥之间存在差异...可能许多密钥映射到同一个哈希桶...内容是密钥(在这种情况下是三元组).. . 所以你所指的“价值观”应该是这些三元组

标签: c# algorithm compression


【解决方案1】:

链式哈希表是存储您放入其中的每个项目的哈希表,即使 2 个项目的键哈希到相同的值,或者即使 2 个项目具有完全相同的键。

DEFLATE 实现需要以无特定顺序存储一堆(键、数据)项目,并快速查找具有该键的所有项目的列表。 在这种情况下,密钥是 3 个连续字节的未压缩明文,数据是某种指针或偏移量,指向该 3 字节子字符串在明文中出现的位置。

许多哈希表/字典实现都存储每个项目的键和数据。 不必为 DEFLATE 将键存储在表中,但除了在压缩过程中使用稍微多一点的内存外,它并没有什么坏处。

一些哈希表/字典实现,例如 C++ STL unordered_map 坚持他们存储的每个(键、数据)项都必须有一个唯一的键。当您尝试使用与表中已有的某个旧项目相同的键存储另一个(键、数据)项目时,这些实现会删除旧项目并将其替换为新项目。 这确实有伤害——如果你不小心使用了 C++ STL unordered_map 或类似的实现,你的压缩文件将会比你使用更合适的库(如 C++ STL hash_multimap)更大。 这样的错误可能难以检测,因为生成的(不必要的大)压缩文件可以通过任何标准 DEFLATE 压缩器正确解压缩为与原始文件逐位相同的文件。 DEFLATE 和其他压缩算法的一些实现故意使用这样的实现,故意牺牲压缩文件的大小来获得压缩速度。

正如尼克约翰逊所说,标准“哈希表”或“字典”实现中使用的默认哈希函数可能绰绰有余。

http://en.wikipedia.org/wiki/Hashtable#Separate_chaining

【讨论】:

    【解决方案2】:

    在这种情况下,他们描述了一个哈希表,其中每个元素都包含一个字符串列表 - 在这种情况下,所有字符串都以指定的三个字符前缀开头。您应该能够使用标准的 .net 哈希表或字典原语 - 无需复制它们的确切实现细节。

    32k 并不是很多数据,因此您不必担心缩放哈希表 - 即使您这样做了,内置原语也可能比您自己编写的任何内容都更有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-03
      • 2013-05-14
      • 1970-01-01
      • 2015-12-31
      • 1970-01-01
      • 2015-07-05
      • 1970-01-01
      • 2020-09-03
      相关资源
      最近更新 更多