【问题标题】:Matches overlapping lookahead on LZ77/LZSS with suffix trees使用后缀树匹配 LZ77/LZSS 上的重叠前瞻
【发布时间】:2015-09-29 14:32:12
【问题描述】:

背景:我在 C++ 上实现了一个通用 LZSS 后端(here 可用。我在这个版本中使用的匹配算法非常简单,因为它最初是为了压缩相对较小的用于相对古老的硬件(特别是 Mega Drive/Sega Genesis,其中 64kB 是整个主 RAM)的文件(最多 64kB)。

尽管如此,在我的实现中,一些文件的压缩时间太长了,大约几分钟。原因有两个:天真的匹配算法花费了大部分时间,但这特别是因为我从文件中构造了一个压缩图以实现最佳压缩。在分析器上,大部分时间都花在寻找匹配上,甚至使结果图的二次大小都相形见绌。

一段时间以来,我一直在研究几种可能的替代品;引起我注意的是dictionary-symbolwise flexible parsing using multilayer suffix trees。多层部分很重要,因为我感兴趣的 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。因此,您的简单实现不应随着文件变大而呈指数级减慢。
  • 我不认为它会触发最坏的情况,而是呈指数级放缓;最坏情况下的简单匹配是 O (mn)(m = 模式长度,n = 搜索文本的长度),并且对文件,所以我以 O (mnp) 结尾——除了文件的开头和结尾。有问题的 LZSS 变体有一个 8192 字节的搜索缓冲区(所以 n = 8192)和一个 256 字节的前瞻缓冲区(所以 m = 256)。对于长度为 p 的文件,最坏的情况是 O (2097152 p),这或多或少是观察到的。
  • 从其他来源获取有趣的方法:github.com/mist64/pucrunch 非常棒。更多信息在这里:koti.kapsi.fi/a1bert/Dev/pucrunch
  • 这是一个有趣的方法。顺便说一句,koti 链接给出了“未找到”错误(但我确实在 Achive.org 上找到了它)。

标签: c++ algorithm suffix-tree lossless-compression lz77


【解决方案1】:

据我了解,给定一棵后缀树,我们(大致)对计算每个后缀 S 感兴趣,较长的后缀与 S 有最长的公共前缀。

将每个树节点的引用添加到具有最长后缀的后代叶子(使用 DFS 的线性时间)。从每个叶子开始,向根部走,检查新的引用,如果找到更长的后缀就停下来。后一步的运行时间是线性的,因为每条树的边缘都只检查一次。

不幸的是,有界窗口的生活更加困难。我们不是传播一个引用,而是传播几个。为了计算从节点引用的后缀集,我们按长度排序将它们合并。然后,只要我们有长度为 x > y > z 的后缀,如果 x - z

如果你想回顾尽可能短的距离,那么有一个 O(n log^2 n) 时间的算法(可能通过各种难以实现的魔法改进到 O(n log n))。在算法过程中,我们为每个节点构造一个按长度计算后代后缀的二叉搜索树,然后进行次长查找。要从其子节点构建节点的树,请从最大的子树开始并插入其他节点的元素。通过heavy path 参数,每个长度被插入 O(log n) 次。

【讨论】:

  • LZ77 和 LZSS 后缀树的使用在文献中得到了很好的稳定;例如,this paper 给出了删除最长后缀的过程,这是滑动窗口所需的步骤之一;使用 Ukkonen 算法的略微修改版本,然后允许添加下一个字符并维护滑动窗口所需的所有树内数据。也就是说,您的想法很有趣,也值得研究。
  • @flamewing 是的,我实际上并没有看,但我认为他们正在做类似的事情。这就是为什么他们不谈论重叠案例的原因——如果操作模式是在线的,那么所需的数据结构尚未构建。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-02
  • 2022-01-24
  • 2013-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多