LZW(Limpel-Ziv-Welch)字典编码分隔符问题

时间:2011-04-19 18:06:22

标签: dictionary compression encoder lzw

此问题可能不严格限于LZW算法,可能涵盖LZ77和LZ78的其他实现:

我一直在尝试编写一个涉及LZW字典编码方案的压缩/解压缩实用程序。 问题是我发现在编码阶段写出每个代码字(或“代码”)之后必须包含一个分隔符(空格)。 我一直这样做是因为我不能假设输出直接流到解码器,并且可以存储在压缩文件中以便稍后解码(在这种情况下,解码器需要一些方法来检测分离的内容)代码字 - 分隔符。

我最近被告知这是不必要的,并且解码器应该能够动态地“弄清楚”每次读取多少压缩文件,可能是基于先前读取的代码。这可以消除在每个代码之后插入额外字节的(代价高昂的)需求。

我只是不确定解码器如何解决这个问题。也许有人了解它的工作原理可以向我解释一下吗?感谢。

编辑:

字典是将“输入字符串”映射到整数(代码)的散列表,并且在读入更多输入数据时以通常的方式构建。字典被写出到压缩文件中。解码器从压缩文件中读取每个代码(整数),并查找其字典以查找要输出的关联字符串,或者如果该代码没有条目,则它会以通常的方式确定字符串应该是什么并更新它的字典。

“如果文件流式传输或存储,为什么会有所不同?” 如果编码器的输出一次一个代码地流到解码器,则解码器可以在接收它们时使用每个代码。但是如果编码器将所有代码写入文件(压缩文件),然后将该文件送入解码器,那么解码器如何知道一个代码的开始位置和另一个代码的开始位置。该文件只是一个混合的数字序列。

例如: 定界压缩文件:127 32 45 22 228 122 209 .... 非定界压缩文件:127324522228122209 ...

-Rob

2 个答案:

答案 0 :(得分:2)

在LZW中,字典不与压缩文件一起存储。 (或者字典文件,依赖于您的观点。)写入文件的每个值都根据其位置具有预定义的位宽。例如,它可以作为9位字典索引对,然后是8位数据开始,直到索引在切换到10位索引时耗尽(发生在精确位置)。

详细信息取决于您如何实施压缩。有些人做一个恒定的12位索引。但在任何情况下都不需要额外的分隔符。

此外,由于数据未在8位边界上对齐,如果您尚未正确读取数据,则无法检测分隔符!

编辑:

如果您希望LZW压缩算法实际生成较小的数据而不是输入,那么您应该做几件事。

首先,您必须将文件写为二进制而不是文本。将其写为文本将扩展而不是缩小文件的大小。值127可以以二进制(01111111)存储在单个字节中,但需要四个字节的UTF-8和一个分隔空格(“127”= 00110001 00110010 00110111 00100000)。

其次,LZW设计用于处理大于一个字节但小于两个字节的代码值,因此必须进行一些比特操作才能正确输出数据。单个字节仅足以编码前256个隐式定义的表条目。另一位将为您提供另外256个条目,但9位索引表中的条目很快就会耗尽。使用12位,您可以获得4096个表条目,这是一个合理的表大小。如果您要使用两个完整字节,那么您将拥有一个包含65 K条目的相当大的表。这样做的问题在于,如果你没有使用表空间的全部容量,那么你就是在浪费时间。输出中有很多位总是为零,这对你的压缩率来说非常糟糕。

第三,流编码器/解码器不能一次执行单个值,因为编码数据与字节边界重叠。如果使用恒定的12位代码大小,则可以一次处理两个编码值的一些倍数。但一般来说,该算法旨在使用完整的文件。

答案 1 :(得分:1)

使用LZW,在读取文件时生成码本,这样就不需要分隔符了。当每个字符添加到LZW输出时,它将从8位转换为更高的位置(通常为10或12位),以便为代码簿提供空间。例如:

banana

在LZW中,b已经在码本中(参考文献2),所以转到baba不在代码簿中,因此请添加它。

目前输出

带有

码本的

ba

27 = ba

(1-26是a-z的索引)

接下来保留a并读取n - > an。这也不在代码簿中,所以它被添加。

目前输出

带有

码本的

ban

27 = ba 28 = an

重复直到结束。结果是:

带有

码本的

bana29

27 = ba  28 = an  29 = na

无需添加分隔符,因为单词bana29已解码,29的查找已存在于代码簿中。

我希望这有助于解释为什么不需要使用LZW进行清除