在后缀树中匹配具有重叠前瞻的LZ77/LZSS算法

8
背景:我有一个通用LZSS后端的C++实现(可在此处找到)。我在此版本中使用的匹配算法非常简单,因为它最初是为了压缩相对较小的文件(最多64kB)而设计的,用于相对古老的硬件(特别是Mega Drive/Sega Genesis,在其中64kB是主RAM的全部内容)。
然而,我的实现有些文件需要花费太长时间进行压缩,大约几分钟。原因是双重的:朴素的匹配算法占用了大部分时间,但这是因为我构建了一个压缩图来实现最佳压缩。查看分析器,大部分时间都花在寻找匹配上,甚至超过了结果图形的平方大小。
我已经研究了几个潜在的替代品一段时间了;其中一个引起了我的注意:使用多层后缀树的字典符号灵活解析。多层部分很重要,因为我感兴趣的LZSS变体之一使用可变长度编码来表示(位置,长度)。
我的当前实现允许滑动窗口中的匹配与前瞻缓冲区重叠,因此,这个输入:
aaaaaaaaaaaaaaaa

可以直接编码为
(0,'a')(1,0,15)

替代

(0,'a')(1,0,1)(1,0,2)(1,0,4)(1,0,8)

在这里,(0,'a')表示将字符'a'编码为文字,而(1,n,m)则表示从位置n开始复制m个字符。

问题:尽管我已经了解了后缀树的一切资源,但它们似乎都无法处理重叠的情况,只能找到非重叠匹配。当涉及到后缀树时,研究论文、书籍甚至一些实现都给出了一些不包含重叠匹配的压缩示例,好像它们是完美的压缩(我可以链接到其中一些,但我的声誉不允许)。其中一些甚至提到重叠可能在描述基本压缩方案时很有用,但在讨论后缀树时却异常沉默。

由于后缀树需要增加偏移信息存储,因此,在查找匹配时可以检查这个特性——过滤掉任何从前向看缓冲区开始的匹配。并且,树的构造/更新方式意味着如果一条边将您带到一个对应于从前向看的匹配开始的节点,那么您将返回先前的节点,因为任何进一步的后代也将位于前视缓冲区。

我的方法是否错误或不正确?是否有一种实现或讨论LZ77/LZSS与后缀树的方法,提到了匹配重叠前视缓冲区?


我不理解第一部分。如果你有一个大文件,你应该将它切成更小的块,每个块不超过64kb。因此,你的简单实现不应该随着文件变得越来越大而呈指数级放缓。 - Barmak Shemirani
我认为它并不是指数级放缓,而是触发了最坏情况;简单匹配在最坏情况下的时间复杂度是O (mn)(m = 模式长度,n = 搜索文本长度),而每个字节都要执行这个操作,所以我最终得到的是O (mnp) —— 除了文件的开头和结尾。讨论中提到的LZSS变体有一个8192字节的搜索缓冲区(因此n = 8192)和一个256字节的前瞻缓冲区(因此m = 256)。对于一个长度为p的文件,最坏情况就是O(2097152 p),这基本上就是观察到的情况。 - flamewing
从其他来源获取有趣的方法:https://github.com/mist64/pucrunch 非常不错。更多信息请参见:http://koti.kapsi.fi/a1bert/Dev/pucrunch/ - Michael Dorgan
那是一个有趣的方法。顺便提一下,Koti链接出现了“未找到”的错误(但我在Achive.org上找到了它)。 - flamewing
1个回答

3
据我所理解,给定一个后缀树,我们大致上想要计算每个后缀 S 的最长公共前缀是哪个更长的后缀。
为每个树节点添加到最长后缀的后代叶子的引用(使用深度优先搜索线性时间)。从每个叶子向根部遍历,检查新引用,如果找到更长的后缀则停止。后一步的运行时间是线性的,因为每个树边只被检查一次。
带有有限窗口的情况不幸更加困难。我们需要传播多个引用而不是一个。为了计算从节点引用的后缀集合,我们按长度排序并合并它们。然后,每当我们有长度为 x > y > z 的后缀时,如果 x - z < 8192(例如),则我们可以丢弃 y,因为对于当前节点是叶子的最近公共祖先的所有后缀来说,这三个后缀都同样好,并且如果 y 在窗口中,则 x 或 z 中的一个也在其中。由于窗口占总文件的很大一部分,因此每个节点最多只有少数几个引用。
如果您想要找到最短的距离,那么有一种O(n log^2 n)时间复杂度的算法(可能可以通过各种难以实现的魔术将其改进为O(n log n))。在算法的过程中,我们为每个节点构建一个后缀子树的二叉搜索树,然后进行下一个最长的查找。为了从子节点构造节点的树,请从最大的子树开始,并插入其他元素。通过重路径的论证,每个长度被插入O(log n)次。

在文献中,使用后缀树进行LZ77和LZSS压缩已经得到了很好的稳定性;例如,这篇论文提供了一种删除最长后缀的过程,这是滑动窗口所需的步骤之一;然后使用稍微修改过的Ukkonen算法,可以添加下一个字符并维护所有必要的树内数据以滑动窗口。话虽如此,您的想法也很有趣,值得进一步研究。 - flamewing
@flamewing 是的,我其实没有看过,但我想他们正在做类似的事情。这就是为什么他们不谈论重叠的情况——如果操作模式是在线的,需要执行该操作的数据结构尚未构建。 - David Eisenstat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接