【问题标题】:Java Binary Search On A Large AbstractList大型 AbstractList 上的 Java 二进制搜索
【发布时间】:2017-04-20 22:20:02
【问题描述】:

短版:

我有一个LinkedListn 随机Integers,按升序排列。
如果我在该列表中使用Collections.binarySearch,它适用于我尝试过的任何n
但是,当我用 AbstractList 包装 LinkedList 时,对于 n>10000,二进制搜索开始表现得非常奇怪。
它不是运行正确的二分搜索,而是遍历整个列表。


加长版:

我有一个"file",其中包含按升序排列的随机数,其中每一行包含一个数字。
我想对 "file" 进行二分搜索并找到给定数字的索引(或 "line number")。

对此的简单解决方案是读取整个文件并将每个数字放入LinkedList,然后在LinkedList 上使用Collections.binarySearch

现在,假设我得到的信息是从 "file" 读取一行是一项昂贵的操作。

为了尽量减少阅读"file" 的时间,我尝试做的是“模拟”LinkedList,并在每次我使用get(int index) 时使用AbstractList 在那个@987654340 @ 我刚刚从"file" 中读到index 行。

当我的AbstractList 大小为<1000 时,这似乎工作得很好,当我尝试更大的列表时,二进制搜索似乎停止工作,并且只是迭代所有AbstractList(从第一个节点到最后)。


我似乎已将问题缩小到使用带有二进制搜索的大型 AbstractList。 我不确定为什么会发生这种情况,希望得到一些帮助。

我已经包含了“长版”,以防有人能够提出其他解决方案。

谢谢!

【问题讨论】:

  • 为什么有理智的人会对LinkedList进行二分搜索?
  • 我只使用了 LinkedList 来模拟我的“文件”。您可以将我描述中的 LinkedList 更改为数组。我在使用 AbstractList 而不是 LinkedList 时会出现问题。
  • 使用更好的“文件”。 LinkedList 具有 O(n) get() - 这与完全遍历相同。因此,您的“二进制搜索”并不比逐行读取文件并查找项目好 - 实际上它更糟糕!这种方法比您的“模拟”有更深层次的问题。没有人。绝对没有人做二进制在磁盘上搜索。
  • @BoristheSpider ,数组列表上的二进制搜索非常快。测试花了很长时间,但我以随机顺序取出所有 1000 万个对象,平均每次获取 1.1300091 毫秒。对于 1Meg 对象,平均为 0.056 毫秒。
  • @oldercoder 我并不否认二分搜索很快。我的意思是对具有 O(n) get 的集合进行二分搜索非常慢。

标签: java linked-list abstract binary-search


【解决方案1】:

Javadoc to the rescue:

[binarySearch] 在 log(n) 时间内运行“随机访问”列表(提供接近恒定时间的位置访问)。如果指定的列表没有实现RandomAccess 接口并且很大,该方法将执行基于迭代器的二分查找,执行O(n) 链接遍历和O(log n) 元素比较。

LinkedListAbstractList 不实现 RandomAccess

【讨论】:

  • 更不用说OP的随机AbstractList hack!
  • 我确实想知道 - 如果二进制搜索 List 而不是 implements RandomAccess,那么有没有时候 not 进行完全遍历是有利的?
  • @AndyTurner 如果包裹LinkedList,那将无济于事。
  • @shmosel 不,实际上它会变得更糟,因为每个“随机”数组访问都需要从列表的开头进行迭代。我只是指出你可以让AbstractList 随机访问。
  • @BoristheSpider 我发现了LinkedList 和包装器之间的区别。 AbstractList 的迭代器是基于索引的,使得非随机访问列表的遍历成为二次方!当然,这完全阻碍了二分搜索的优化尝试。我想知道将列表复制到一个临时数组中是否会更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多