Java中如何从这个ArrayList中快速知道海量ArrayList中的索引?

How to quickly know the indexes in a massive ArrayList of a very large number of strings from this ArrayList in Java?

假设我在 Java ArrayList 中收集了 5000 万个不同的字符串。设 foo 为一组 4000 万个从先前集合中任意选择(但固定)的字符串。我想知道 ArrayList 中 foo 中每个字符串的索引。

一个明显的方法是遍历整个 ArrayList,直到我们在 foo 中找到第一个字符串的匹配项,然后是第二个字符串,依此类推。然而,这个解决方案将花费非常长的时间(同时考虑到 5000 万是我为示例选择的任意大数,集合可能在数亿甚至数十亿的数量级,但这是从一开始就给出的并且保持不变)。

然后我想到使用固定大小为 5000 万的哈希表,以便使用 someStringInFoo.hashCode() 确定 foo 中给定字符串的索引。但是,根据我对 Java 的哈希表的理解,如果发生冲突,这似乎会失败,因为调用 hashCode() 将为两个不同的字符串生成相同的索引。

最后,我想到先用Java的Collections中的sort(List<T> list)对ArrayList进行排序,然后用binarySearch(List<? extends T> list,T key,Comparator<? super T> c)获取term的索引。有没有比这更有效的解决方案,或者这已经很好了吗?

您可以毫无问题地使用 Java 哈希 table。根据 Java 文档 "in the case of a "hash collision",单个桶存储多个条目,必须按顺序搜索。"

我认为您对散列 table 的工作原理有误解。哈希冲突不会破坏实现。散列 table 只是 linked-lists 的数组。每个键都通过散列函数来确定元素将放置在数组中的索引。如果发生散列冲突,该元素将被放置在 hash-table 数组中索引处 linked-list 的末尾。请参阅下面的 link 图表。

您需要为搜索字符串而优化的其他数据结构。它会将字符串映射到它的索引。这个想法是你迭代你的原始列表来填充你的数据结构,然后迭代你的集合,在该数据结构中执行搜索。

你应该选择什么结构?

有三个选项值得考虑:

第一个选项实施起来很简单,但没有提供最好的性能。但是,它的填充时间 O(N * R) 优于对列表进行排序,即 O(R * N * log N)。搜索时间比在排序的字符串列表中更好(与 O(R log N) 相比,分摊 O(R)。 其中 R 是字符串的平均长度。

第二个选项始终适用于字符串映射,为 O(R * N) 的情况提供保证的填充时间,并保证 O(R) 的最坏情况搜索时间。它唯一的缺点是 Java 标准库中没有开箱即用的实现。

第三个选项有点棘手,只适合你的情况。为了使其工作,您需要确保第一个列表中的字符串在第二个列表中按字面意义使用(是相同的对象)。使用 IdentityHashMap 消除了 String 的相等成本(上面的 R),因为 IdentityHashMap 按地址比较字符串,仅采用 O(1)。人口成本将摊销 O(N) 和搜索成本摊销 O(1)。因此,该解决方案提供了最佳性能和开箱即用的实施。但是请注意,此解决方案仅在原始列表中没有重复项时才有效。

如果您有任何问题,请告诉我。