LZ78 的一个快速但足够的定义来自维基百科:
每个字典条目的格式为 dictionary[...] = {index, character},其中 index 是前一个字典条目的索引,而 character 附加到由 dictionary[index] 表示的字符串中。例如,“abc”将按如下方式存储(以相反的顺序):dictionary[k] = {j, 'c'}, dictionary[j] = {i, 'b'}, dictionary[i] = {0 , 'a'},其中索引 0 指定字符串的第一个字符。该算法初始化最后一个匹配索引= 0 和下一个可用索引= 1。
对于输入流的每个字符,在字典中搜索匹配项:{ last matching index , character}。
如果找到匹配项,则将最后一个匹配索引设置为匹配条目的索引,并且不输出任何内容。
如果没有找到匹配项,则创建一个新的字典条目:dictionary[ next available index ] = { last matching index , character},算法输出最后一个匹配索引,后跟字符,然后重置最后一个匹配索引= 0 和递增下一个可用索引。一旦字典已满,就不再添加条目。
当到达输入流的末尾时,算法输出最后一个匹配索引。
在考虑实施时,最后一句话对我来说是一个严重的问题。好的,输出流的形式是 (index,letter)...(index,letter)(index)。
但是在一般情况下,由于任何实现都需要使用字节(或类似的,这并不重要),我们有一个填充。那么如何让解码器不被填充所迷惑呢?
我知道存在一些技巧,例如,如果我有原始字符串的总长度,那么很容易停止解码器。但是,在这种情况下,LZ78 不再是流压缩器。另一个例子是扩展字母表,使其在终端情况下具有特殊的字符,但这将至少多使用一位来进行字母编码,这对我来说是不可接受的。同样,如果字符集包含所有可能的字节,则没有问题,因为任何输出步骤都会生成至少 8 位(索引+字母),因此很容易知道我们是否在末尾。
但在 LZ78 的一般情况下,您可以使用任何字母表。例如,如果字母表只有两个元素 0 和 1,我无法理解如何不被填充所迷惑。我的意思是如何区分(索引,填充)和(索引,字母)?
如何区分00和000的编码?
- (0,0)(1)+填充(原始:001+填充)
- (0,0)(1,0)+填充(原始:0010+填充)
我错过了一个非常简单的观点吗?
请注意,即使是 Lempel & Ziv 的原始论文,也没有提及这一点。我发现和分析的所有实现都使用了我列出的技巧之一(或变体)。