【问题标题】:Space efficient collection for strings with common prefixes - Java implementation具有公共前缀的字符串的空间高效收集 - Java 实现
【发布时间】:2011-08-01 12:48:06
【问题描述】:

我需要将数百万个带有公共前缀的字符串(它们不对应于文件系统路径)存储在内存中的类似 Set 的结构中,并查询 Collection 以查看是否存在路径。

例如

/path
/path/1
/path/2
/path/1/a
/path/1/b

我想尽可能高效地存储这些(它们将在内存中),考虑到所有涉及的字符串都会有许多公共前缀,Trie 是否是一个合理的候选者?

我正在寻找一个建议在 Java 中实现合适的数据结构。

【问题讨论】:

标签: java data-structures collections trie


【解决方案1】:

Trie 看起来像您需要的结构。类似的结构还有Radix Tries,与尝试不同的是,它使用字符序列来标记边缘。在简单的尝试中,边缘用单个字符标记,我相信在字符串共享很多前缀的情况下它们会表现得更好。

另见...

http://code.google.com/p/trie/

http://code.google.com/p/radixtree/

【讨论】:

  • 作者的评论并没有激发太多的信心! “任何访问者请注意,这是很好的 SAMPLE 代码,但不是生产代码。它是由一个没有经验的程序员(当时是我)在一个晚上编写的。”
  • 是的,你是对的......去 Radix Tries(第二个链接)它们实际上更适合这种情况。
  • 有什么理由更喜欢基数树的第二种实现而不是这个? code.google.com/p/patricia-trie
  • 但是 both 都是基数尝试(又名 Patricia-Trie),只是实现不同......
  • 不,它们是不同的。第一个只是“trie”,第二个是“radix trie”。查看维基百科的解释,您将很容易发现差异。
【解决方案2】:

这看起来是一个不错的候选实现:https://github.com/rkapsi/patricia-trie

【讨论】:

    【解决方案3】:

    在提出任何建议之前,让我们考虑一下权衡。

    您说您需要存储“数百万”条路径。我假设有一百万,因为它使计算更容易(即使在服务器上,我也没有看到超过一百万的目录)。

    这些路径有多长?您已经展示了一个路径非常短的示例,因此我们正在查看可能有一百兆字节来存储这百万条路径。我没有关于最大路径长度的参考,但 256 个字符在我脑海中挥之不去。因此,您的路径最多将占用 512 Mb 的内存。你有那么大的记忆力吗?

    路径名的分布有多均匀?换句话说,您是否遵循 80:20 规则,即在 20% 的目录中找到 80% 的路径?我问的原因是因为 trie 结构需要某种形式的级别之间的索引。如果您有很多目录,而它们下面只有几条路径,那么您将有很多开销来维护 trie。

    建议:如果我有足够的内存,我会使用 HashSet<String> 并完成它。

    如果我没有很多内存,并且没有遵循 80:20 规则(或者,更有可能是 95:5)的目录结构,我会想到 HashMap<String,Set<String>>。此映射的键将是具有“合理”重复量的最长前导路径字符串,而值将是剩余的字符串。您将使用逐渐变短的前导组件来探测此地图,直到找到匹配项,然后探测其余部分的集合。

    这就留下了“合理”重复的问题。这是重复的数量,其中两部分数据结构的开销被重复的减少所克服。例如,/usr/bin/ 可能有效(因为它包含数千个文件,并且每个文件保存 9 个字符或 18 个字节),但 /usr/local/bin/ 可能不会有效(至少在我的系统上,它只包含一个文件)。

    【讨论】:

      【解决方案4】:

      您可以使用树结构,就像在磁盘上一样。但是,您需要记住,树结构可以在开销中使用尽可能多或更多的内存,因为它们可以节省。也就是说,它们并不是真正为节省内存而设计的。

      如果这些文件存在,也许您可​​以使用磁盘子系统的缓存。它可能会更快。

      我会检查您是否真的需要这样做,因为您可以非常轻松地在 JVM 中存储一百万个条目。 ;)

      如果你想最小化内存消耗,你可以压缩内存中的数据。这可能比任何其他选项都要小得多,但要提高效率则要复杂得多。

      【讨论】:

      • 我可能会有几千万条记录,而且资源有限。
      • 我会考虑使用压缩,你不会比这更小。
      • 我需要避免过多的处理,因为我会经常创建和销毁这些集合。
      • 知道最新版本的 Oracle JVM 可以使用 byte[] 而不是 char[] 来表示字符串。可以用最后一个JVM吗?
      • 拥有适合这项工作的正确工具也很重要。来自主要供应商的具有 8 GB 内存的服务器成本约为 430 英镑。 ;)
      【解决方案5】:

      我会用什么:

      1. 类似于 目录结构。
      2. 单平衡树 字符作为键和进一步的树 作为值。

      【讨论】:

        【解决方案6】:

        我建议您将路径按原样存储为字符串。我相信试图节省内存的开销会导致相反的结果。

        当然,通过对上面提到的 Tries 数据结构进行基准测试来测试它是否是很简单的。

        【讨论】:

        • "我相信试图节省内存的开销会导致相反的结果。"为什么?
        • 指向子节点的指针可能比子节点本身大。
        猜你喜欢
        • 2021-01-13
        • 1970-01-01
        • 2020-11-13
        • 2020-06-06
        • 1970-01-01
        • 1970-01-01
        • 2020-12-12
        • 2012-01-24
        • 1970-01-01
        相关资源
        最近更新 更多