具有公共前缀的字符串的空间高效集合 - Java实现

时间:2011-04-08 13:30:27

标签: java data-structures collections trie

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

e.g。

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

我想尽可能有效地存储它们(它们将存储在内存中),因为如果Trie是合理的候选者,所涉及的所有字符串都会有许多共同的前缀?

我正在寻找一个推荐用于Java的合适数据结构的实现

6 个答案:

答案 0 :(得分:4)

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

另见......

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

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

答案 1 :(得分:3)

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

答案 2 :(得分:1)

让我们在任何建议之前考虑权衡。

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

这些路径有多长?你已经展示了一个非常短的路径的例子,所以我们可能会看到一百兆字节来存储这些百万路径。我没有最大路径长度的参考,但我心中有256个字符。因此,您的路径将占用最多512 Mb的内存。你有那么多记忆吗?

路径名的均匀分布情况如何?换句话说,您是否遵循80:20规则,其中80%的路径在20%的目录中找到?我问的原因是因为trie结构需要在级别之间使用某种形式的索引。如果你有很多目录只有几条路径,你将需要很多开销来维护一个trie。

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

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

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

答案 3 :(得分:0)

您可以使用树结构,就像在磁盘上一样。但是,您需要记住,树结构可以在节省开销时使用尽可能多的内存。即它们并不是为了节省记忆而设计的。

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

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

如果要最小化内存消耗,可以压缩内存中的数据。这可能比任何其他选项小得多,但制作效率更加复杂。

答案 4 :(得分:0)

我会用什么:

  1. 类似于的多层地图 目录结构。
  2. 单一的平衡树 字符作为键和更多树 作为价值观。

答案 5 :(得分:0)

我建议你按原样存储路径,如字符串。我相信试图节省内存的开销会导致相反的情况。

当然,通过对上述Tries数据结构进行基准测试,可以很容易地测试它是否存在。