文本打包算法
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')。
【讨论】:
以上是关于文本打包算法的主要内容,如果未能解决你的问题,请参考以下文章