我目前正在尝试在C#中创建自定义Deflate实现。
我目前正在尝试实现“模式搜索”部分,我有(最多)32k的数据,并且我正在尝试为我的输入搜索最长的模式。
定义Deflate的RFC 1951说明了该过程:
压缩器使用链式哈希表来查找重复的字符串, 使用对3字节序列进行操作的散列函数。在任何 在压缩期间给定点,让XYZ成为接下来的3个输入字节 进行检查(当然不一定都是不同的)。首先, 压缩器检查XYZ的哈希链。如果链是空的, 压缩器只是将X写为文字字节并前进一个 输入中的字节。如果哈希链不为空,则表明 序列XYZ(或者,如果我们运气不好,还有其他3个字节 最近发生了相同的哈希函数值)压缩器 将XYZ哈希链上的所有字符串与实际输入数据进行比较 序列从当前点开始,并选择最长的序列 匹配。
我知道哈希函数是什么,并且知道HashTable是什么。但什么是“链式哈希表”以及如何将这样的结构设计为高效(在C#中)处理大量数据?不幸的是,我不明白RFC中描述的结构是如何工作的。
我可以选择什么样的哈希函数(什么才有意义)?
提前谢谢!
答案 0 :(得分:3)
链式哈希表是一个哈希表,它存储您放入其中的每个项目,即使两个项目的密钥哈希值相同,或者即使两个项目具有完全相同的密钥。
DEFLATE实现需要以特定顺序存储一堆(密钥,数据)项,并快速查找具有该密钥的所有项的列表。 在这种情况下,密钥是3个连续字节的未压缩明文,数据是某种指针或偏移到明文中出现3字节子字符串的位置。
许多散列表/字典实现都存储了每个项目的密钥和数据。 没有必要将密钥存储在DEFLATE表中,但除了在压缩期间使用稍多的内存外,它不会造成任何损害。
某些散列表/字典实现(例如C ++ STL unordered_map
坚持认为它们存储的每个(键,数据)项必须具有唯一键。当您尝试使用与表中已有的旧项相同的键存储另一个(键,数据)项时,这些实现将删除旧项并将其替换为新项。
那个会受到伤害 - 如果你不小心使用了C ++ STL unordered_map
或类似的实现,你的压缩文件会比使用更合适的库(如C ++ STL {{更大)。 1}}。
这样的错误可能难以检测,因为所得到的(不必要的大)压缩文件可以被任何标准DEFLATE压缩器正确解压缩到与原始文件相同的文件。
DEFLATE和其他压缩算法的一些实现故意使用这样的实现,故意牺牲压缩文件大小以获得压缩速度。
正如Nick Johnson所说,标准“哈希表”或“词典”实现中使用的默认哈希函数可能已经足够了。
答案 1 :(得分:2)
在这种情况下,他们描述了一个哈希表,其中每个元素都包含一个字符串列表 - 在这种情况下,所有字符串都以指定的三个字符前缀开头。您应该只需使用标准的.net哈希表或字典原语 - 无需复制其确切的实现细节。
32k并不是很多数据,因此您不必担心扩展哈希表 - 即使您这样做,内置基元也可能比您自己编写的任何内容都更有效。