“对LZ77回指,先验证距离 $1\le d\le\min(W,p)$、长度范围和剩余输出/工作,再逐字节复制。对LZ78,先验证旧编号已经存在;利用条目中保存的短语长度计算展开长度,通过预算…”
形式陈述
LZ77类编码把输入字节串解析成字面量和对已输出历史的回指。本页采用常见的二类token变体:Lit(b)直接输出字节 Match(ℓ,d)从当前位置向前距离
长度下限3是本教学解析器的约定,不是所有LZ变体的定义。编码端还限定最大匹配长
当 out[-d],追加到末尾”。不能在复制前只截取一份历史子串,再误以为它已有
给定token和足够的输出容量,解码结果由上述转移唯一确定。编码解析却可能有多种选择:发字面量、使用短匹配或长匹配,都可能恢复同一个原文;不同解析的bit费用要由后续token编码决定。
直觉
距离回答“回头多少格”,长度回答“往前写多少格”。回头的位置不是固定快照,而是随写指针一起前移。于是一个短周期就可以自我扩展:历史里只有AB,也足以再生出ABABABA。
编码器需要找匹配,解码器只需要按已经给出的指针复制。找最长匹配属于字符串匹配问题;不能把编码端可能昂贵的搜索成本加到每次解码的定义里,也不能把解码的简单性反过来当作免费搜索算法。
例子与边界
窗口 ABABABABA 编成 Lit(A), Lit(B), Match(7,2)。读入两个字面量后,
- 写位置2,从0读A;输出ABA
- 写位置3,从1读B;输出ABAB
- 写位置4,从2读A;这个A是第一步刚写入的
- 写位置5、6、7、8,分别从3、4、5、6读B、A、B、A
最后输出九字节 ABABABABA。一次性复制原历史切片 out[0:7] 只能拿到AB,无法实现这个token。若一概拒绝
距离0没有本页定义的历史源,必须拒绝。输出还为空时,任何正距离都无效。已有一个字节时距离2也无效;“它还在文件中某处”并不等于“已经解出并在窗口中”。空文件用空token序列得到空输出,停止方式由外层格式规定。对单字母长串可以发一个A,再用距离1的匹配扩展。
长度与距离还需要编码成bit。例如DEFLATE把长度11表示为长度符号265加1个扩展bit,基值11,扩展值0;距离6表示为距离符号4加1个扩展bit,基值5,扩展值1。总费用是两个符号各自的Huffman码长再加2bit,不能仅数“一个匹配token”。本单元只复算这项参数映射,不输出DEFLATE块。
推论与应用
复制为何唯一且保持原文
对匹配内的位置
用朴素搜索在每个输入位置尝试至多
贪心最长匹配减少当前位置的未处理字节数,不自动最小化最终bit数:更长匹配可能需要昂贵的长度或距离符号,也可能错过下一位置更省的匹配。若要证明最优解析,需要把token费用和未来状态写进优化问题。
回指长度来自不可信文件时,先检查