文本打包算法

Posted

技术标签:

【中文标题】文本打包算法【英文标题】:Text packing algorithm 【发布时间】:2010-10-25 02:59:20 【问题描述】:

我敢打赌以前有人解决过这个问题,但我的搜索结果是空的。

我想将单词列表打包到缓冲区中,跟踪每个单词的起始位置和长度。诀窍是我想通过消除冗余来有效地打包缓冲区。

示例:娃娃屋

这些可以像dollhouse一样打包到缓冲区中,记住doll是从位置0开始的四个字母,dollhouse是从位置0开始的九个字母,house是从位置3开始的五个字母。

到目前为止,我想出的是:

    将单词从最长到最短排序:(娃娃屋、房子、娃娃) 扫描缓冲区以查看字符串是否已作为子字符串存在,如果存在,请记下位置。 如果不存在,请将其添加到缓冲区的末尾。

由于长词通常包含较短的词,因此效果很好,但应该可以做得更好。例如,如果我将单词列表扩展为包含 ragdoll,那么我的算法会得出dollhouseragdoll,它的效率低于ragdollhouse

这是一个预处理步骤,所以我并不十分担心速度。 O(n^2) 很好。另一方面,我的实际列表有数万个单词,所以 O(n!) 可能是不可能的。

附带说明,此存储方案用于 TrueType 字体的“名称”表中的数据,参见。 http://www.microsoft.com/typography/otspec/name.htm

【问题讨论】:

你不能只使用 gzip 之类的东西吗? 您所描述的是所有压缩算法所做的,除了您添加了将纯文本单词视为被压缩的元素而不是位的约束。 它与压缩算法不太一样,因为每个单词都必须保持其“冗长”。就像我在另一条评论中所说的那样,您不能将“lawman”和“woman”组合在一起,但在压缩中,将“man”压缩在一起就可以了,因为您不需要保持一个一致的缓冲区。 另外,FWIW,该解决方案应该能够利用多个后缀和前缀匹配。所以如果我的词表有“lawman”、“woman”、“manage”和“mangle”,它应该能够形成“lawmanage”和“womangle”。 @Adrian:这是错误的区分。是的,您可以通过访问索引来就地解压缩索引打包数据,我同意这个方案特别适合这种用途,但它仍然是压缩;有一个处理步骤来访问原始数据。其他压缩也可以就地完成。 【参考方案1】:

我认为您可以使用Radix Tree。由于指向叶子和父节点的指针,它会占用一些内存,但匹配字符串很容易(O(k)(其中 k 是最长的字符串大小)。

【讨论】:

我相信这只适用于以公共子字符串开头的字符串。无法识别以公共子字符串结尾的字符串。如果我错了,请纠正我。 如果字符串以公共子字符串结尾,则根据此描述,它们无论如何都不会匹配。这样做会导致各个字符串变得混乱。 详细来说,如果你有“女人”和“律师”,即使你想也不能把它们结合起来。组合起作用的唯一方法(据我所知)是一个词的后缀与另一个词的前缀匹配。【参考方案2】:

我的第一个想法是:使用数据结构来确定字符串的常见前缀和后缀。然后根据这些前缀和后缀对单词进行排序。这将产生您想要的ragdollhouse

【讨论】:

您的建议听起来可以用双基数树(一个向前和向后)来实现。这在大多数情况下都有效,但如果字符串在中间有公共部分,但在边缘没有,则将不起作用。 例如,它不会识别消费和求和。【参考方案3】:

看起来类似于Knapsack problem,是NP完全的,所以没有“确定性”算法。

【讨论】:

您能向我们解释一下背包问题的链接吗? 背包问题(最好将一些货物装在袋子里)看起来和我很相似。事实上(见 j_random_hacker 的回答)这是一个 NP 完全问题,就像背包问题一样。 是的,但我仍然看不出这个问题与 KP 的相似之处。 3-SAT是NPC,但我不能肯定地说它类似于“字符串打包”问题。 “bag”是长度最短的字符串(“最佳打包”字符串)。将货物装入袋中类似于调整“主”之一中的子字符串:在这两种情况下,您都有约束(子字符串约束或总重量限制)。 恕我直言,子字符串约束使问题的性质大不相同,但没关系;)【参考方案4】:

我在大学时做过一个实验室,我们的任务是实施一个简单的压缩程序。

我们所做的是按顺序将这些技术应用于文本:

BWT (Burrows-Wheeler transform):帮助将字母重新排序为相同字母的序列(提示*有数学替换来获取字母,而不是实际进行旋转) MTF (Move to front transform):将字母序列重写为动态列表的索引序列。 Huffman encoding:熵编码的一种形式,它构造了一个可变长度的代码表,其中较短的代码被赋予频繁出现的符号,较长的代码被赋予不经常出现的符号

在这里,我找到了assignment page。

要取回原始文本,您需要执行 (1) Huffman 解码,(2) 逆 MTF,然后 (3) 逆 BWT。 Interwebs 上有几个很好的资源。

【讨论】:

很有趣,但与手头的问题几乎无关。此外,通常在 MTF 之前放置一个运行长度编码步骤。 :)【参考方案5】:

这是最短超字符串问题:找到包含一组给定字符串作为子字符串的最短字符串。根据this IEEE paper(不幸的是,您可能无法访问),解决这个问题正是NP-complete。但是,可以使用启发式解决方案。

作为第一步,您应该找到所有属于其他字符串的子字符串的字符串并将其删除(当然您仍然需要以某种方式记录它们相对于包含字符串的位置)。使用generalised suffix tree 可以有效地找到这些完全包含的字符串。

然后,通过重复合并两个重叠最长的字符串,可以保证生成一个长度不小于最小可能长度的 4 倍的解。正如 Zifre 在Konrad Rudolph's answer 上的评论所建议的那样,使用两棵基数树应该可以快速找到重叠大小。或者,您也许能够以某种方式使用广义后缀树。

很抱歉,我无法为您找到一个像样的链接 - 似乎没有 Wikipedia 页面,也没有关于此特定问题的任何可公开访问的信息。简要提及here,但没有提供建议的解决方案。

【讨论】:

谢谢!为问题命名总是一个好的开始。我认为一个完美的解决方案可能遥不可及,但一个好的解决方案会令人满意。【参考方案6】:

我不会再重新发明这个***了。压缩算法已经投入了大量的人力,为什么不采用一种已经可用的算法呢?

这里有几个不错的选择:

gzip 用于快速压缩/解压缩速度 bzip2 压缩有点苦,但解压速度要慢得多 LZMA 用于非常高的压缩比和快速解压缩(比 bzip2 快但比 gzip 慢) lzop 用于非常快速的压缩/解压缩

如果你使用 Java,gzip is already integrated。

【讨论】:

我不是在打包,不是压缩。在运行时,我希望每个单词的全文都易于访问。我可以在没有任何包装的情况下做到这一点,但我认识到包装可以显着减少占用空间并改善参考位置。 您的打包和解包与任何其他压缩和解压缩算法有何不同? 使用压缩,你必须解压缩。正如我所描述的那样包装,不需要拆包。我有原文的全文直接可用。【参考方案7】:

不清楚你想做什么。

您是否想要一种数据结构,让您以有记忆力的方式存储字符串,同时让搜索等操作在合理的时间内成为可能?

您只需要压缩的单词数组吗?

在第一种情况下,您可以选择 patricia trie 或 String B-Tree。

对于第二种情况,你可以采用一些索引压缩技术,像这样:

如果你有类似的东西:

aaa 
aaab
aasd
abaco
abad

你可以这样压缩:

0aaa
3b
2sd
1baco
2ad

数字是前面字符串的最大公共前缀的长度。 例如,您可以调整该架构。计划在 K 个单词之后“重新启动”公共前缀,以便快速重建

【讨论】:

请注意,对于最后一个模式,您应该压缩的不仅仅是您建议的打包。当然你不能只有一个指向单词的指针,而是一个元组(指向带有 0 前缀的第一个单词的指针,偏移量) 我不是在寻找压缩方法。我需要快速随机访问每个单词的全文,所以我不想即时解压缩。打包减少了内存占用并提高了引用的局部性。 你确定它可以改善局部性吗?位置很大程度上取决于您请求单词的顺序,而不仅仅是内存占用(当然,边缘情况除外)。你真的确定它会大大改善内存占用吗?在我看来,如果你有一组特定的字符串,这种优化可能是一件好事,但它实际上是无用的,例如,自然语言单词。【参考方案8】:

细化第 3 步。

查看当前列表,查看列表中是否有任何单词以当前单词的后缀开头。 (您可能希望使后缀长于某个长度 - 例如,长于 1)。 如果是,则添加该单词的不同前缀作为现有单词的前缀,并适当调整所有现有引用(慢!) 如果否,则按照当前步骤 3 将单词添加到列表末尾。

这将为您提供“ragdollhouse”作为示例中的存储数据。目前尚不清楚它是否总是能以最佳方式工作(例如,如果您在单词列表中还有 'barbiedoll' 和 'dollar')。

【讨论】:

以上是关于文本打包算法的主要内容,如果未能解决你的问题,请参考以下文章

以质量增量打包图像的算法

Linux下打包和解压

什么算法可用于以相当优化的方式将不同大小的矩形打包成最小的矩形?

C#如何用程序把文本文件打包成dll文件

算法和数据结构_18_小算法_源代码打包下载

将矩形图像数据打包成方形纹理