【问题标题】:Memory and speed efficient search on Strings对字符串进行内存和速度高效搜索
【发布时间】:2012-08-10 19:00:25
【问题描述】:

我有一堆Strings 我想快速查找。每个字符串的长度为 22 个字符,仅由前 12 个字符(可以说是“键”)查找,并且会定期重新创建完整的字符串集。它们从文件中加载并在文件更改时刷新。我必须处理太少的可用内存,我的 VPS 上的其他服务器进程也需要它并且需要它更多。

如何最好地存储字符串并搜索它们?

我目前的想法是将它们一个接一个地存储在 char[] 中(以节省 RAM),并对它们进行排序以便更快地查找(我认为如果我将它们预先排序,则查找速度最快,因此我可以使用 binaryinterpolation 搜索)。但我不完全确定我应该如何编码 - 如果有人想要一个具有挑战性的难题:这里是......

顺便说一句:在娱乐/排序期间超出内存限制一段时间可能是可以的,但不应过多或过长时间。

谢谢!

更新

对于“我想知道细节”的人群(如果我在 Java 详细信息中有错误,请纠正我):源文件包含大约 320 000 个条目(所有 ANSI 文本),我真的很想留下来(WAY!)低于 64 MB 的 RAM 使用率,数据只是我程序的一部分。以下是内存中sizes of Java types 的一些信息。

我的 VPS 是 32 位操作系统,所以...

  • 一个byte[],全部连接 = 12 + 长度字节
  • 一个char[],全部连接 = 12 + 长度 * 2 个字节
  • String = 32 + 长度 * 2 字节(是 Object,有 char[] + 3 int

所以我必须记住:

  • ~7 MB 如果全部存储在byte[]
  • ~14 MB 如果全部存储在char[]
  • ~25 MB 如果全部存储在String[]
  • > 40 MB,如果它们存储在 HashTable / Map 中(我可能需要微调初始容量)

HashTable 并不神奇 - 它有助于插入,但原则上它只是一个非常长的 String 数组,其中 hashCode 模容量用作索引,数据存储在索引之后的下一个空闲位置并被搜索如果在查找时找不到它,则为线性。但是对于哈希表,我需要字符串本身和前 12 个字符的子字符串进行查找。我不想要那个(或者我在这里错过了什么?),对不起,伙计们......

【问题讨论】:

  • 如果您(一次)只根据您所面临的一个狭窄问题(例如:内存使用、排序算法、数据结构)提出一个问题,这将有所帮助。
  • 哈希表有什么问题吗?另外,您的性能是否受到限制?
  • 我没有性能限制,但它仍然不应该花太长时间。 HashTable 对我不起作用(请参阅上面的更新)。
  • @AaronKurtzhals:我认为这不会有帮助,因为决策会相互影响。但我希望关于我的限制的其他信息会有所帮助。
  • 您对哈希表的厌恶很难理解。事实上,除非哈希码是退化的,否则它们对于插入和查找都是 O(1)。

标签: java algorithm data-structures size space-efficiency


【解决方案1】:

我可能会为此使用缓存解决方案,甚至可能是番石榴。当然对它们进行排序,然后是二进制搜索。可惜我没时间 :(

【讨论】:

    【解决方案2】:

    听起来像HashTable 将是这种情况下的正确实现。

    搜索在恒定时间内完成,刷新可以在线性时间内完成。

    Java Data Structure Big-O(警告 PDF)

    【讨论】:

      【解决方案3】:

      我自己编写了一个解决方案 - 但它与我发布的问题有点不同,因为我可以使用我没有发布的信息(我下次会做得更好,抱歉)。

      我只是回答这个问题,因为它已经解决了,我不会接受其他答案之一,因为它们对内存限制没有真正的帮助(而且对我的口味来说有点短)。他们仍然得到了每个人的支持,没有难过的感觉,感谢您抽出宝贵的时间!

      我设法将所有信息推入两个长字节(密钥完全位于第一个长字节中)。前 12 个字符是一个 ISIN,可以压缩成一个长字符,因为它只使用数字和大写字母,总是以两个大写字母开头,以一个可以从其他字符重构的数字结尾。所有可能值的乘积留下了略多于 3 位的余量。

      我将源文件中的所有条目存储在 long[] 中(首先打包 ISIN,第二个 long 中包含其他内容)并根据两个 long 中的第一个对它们进行排序。

      当我通过键进行查询时,我将其转换为 long,进行二进制搜索(我可能会更改为插值搜索)并返回匹配的索引。值的不同部分可以通过所述索引检索 - 我从数组中获取第二个 long,解包并返回请求的数据。

      结果:RAM 使用量从 ~110 MB 下降到

      【讨论】:

      • 这可能是最佳选择,但使用两个 long[] 会容易得多,因为您可以使用现有的排序和 binarySearch(以每次查找的 L3 缓存未命中为代价)。
      • 不,不会。两个 long 必须彼此相邻(所以我使用indexindex + 1 获取所有数据)。如果我将其拆分为两个数组并使用现有的sortbinarySearch,它们将独立排序并且关联丢失。
      • 你是对的。关于排序,您需要一个临时的HashMap 来创建第二个long[],这会临时占用大量内存。或者您自己的排序同时处理两个数组,但这是我想要避免的。
      猜你喜欢
      • 2016-04-19
      • 1970-01-01
      • 2020-06-01
      • 1970-01-01
      • 2018-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多