使用5100万个素数快速迭代数据结构

时间:2009-07-04 02:20:02

标签: java data-structures primes

用于加载5100万个素数然后迭代它们的任务的最佳数据结构(在java中)是什么?

我需要知道,例如,在1000000000和相同数字减去100000之间的素数。

11 个答案:

答案 0 :(得分:6)

二进制搜索对于这些数据来说并不是很好,因为素数的前半部分将比它们的后半部分更接近彼此。

您可以通过了解how many primes there are under x来改进搜索。也许使用链接中提到的近似值来削减切割。


我的第一次尝试就是这样。我有两个阵列。

  1. 所有素数的数组。
  2. 一个数组,告诉我在第一个数组中1000 * n以上的第一个素数在哪里。所以,如果我想找到值为5000或更高的第一个素数,我会看看secondArray [5000 / 1000-1]。
  3. 在对数组1做任何事情之前,我会得到数组2的粗略位置。

答案 1 :(得分:3)

为什么要将它们存放在地图中?这是为了让您快速查找以查看是否有任何给定数字是素数?这将是有道理的,并为您提供快速访问。通过设置TreeMap的初始容量,可以减轻(但不能消除)添加它们的成本。然而,这仍将导致树再平衡成本。

替代存储可能只是对它们进行排序并将它们放入数组中。这将使您通过二分搜索进行O(log n)查找,但会使得范围变得微不足道。您可以使用Arrays.binarySearch()

答案 2 :(得分:3)

既然你可以预先计算所有素数,并且(通过Nosredna和其他人提到过的素数定理)你知道将会有多少素数,你可以使用一个固定的结构(int [])和一次性订单插入成本不应该是一个问题。

二进制搜索(As Arrays.binarySearch())会非常快,您可能不需要考虑优化。但是,你也可以使用素数定理的大致预测,即Nth prime更快地找到范围的端点。

只是为了与众不同,我要指出,在这个比例下,您还可以将素数作为设置位存储在一个大位域中,其中如果N是素数,则位#N设置为1.结构实际上是小于int [] - 10亿比特是~110MiB,而5100万比特是〜200MiB。请参阅类BitSet。因为没有偶数索引是素数,所以你可以子类化或包装BitSet,在传递到/从BitSet传递之前,为所有偶数索引和半/双值提供简单的答案,从而将整个字段存储在~55MiB中。

使用这样的结构测试素数是O(1),但迭代所有设置位(素数)取决于您所针对的范围中质数的密度。它仍然应该很快。

答案 3 :(得分:1)

对我来说,一个简单的数组(或ArrayList,因为它更容易使用)会很好。添加元素是O(1),您可以通过对第一个素数> = x(参见http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collections.html#binarySearch%28java.util.List,%20T%29)进行二元搜索来获得x和y之间的所有素数,然后只需通过列表直到获得到一个黄金>年。

(我意识到cletus打败了我,但希望额外的细节有用。)

答案 4 :(得分:1)

第n个素数约为p(n) ~ n ln(n),即

p(51E6) ~ 905114146 < 2147483647 = Integer.MAX_VALUE

这意味着存储前5100万个素数的最有效方法是int[]

答案 5 :(得分:1)

这完全取决于操作和使用的平衡。一个简单的排序数组最适合存储素数。

现在,如果性能真的很高,内存成本微不足道,那么你可以用索引索引来增加它。 e.g。

int MAX_NUM_PRIMES =    ...   // the maximum number of primes to be stored
int MAX_PRIME = ....          // the largest prime to be stored
int primes[MAX_NUM_PRIMES]    // array of prime numbers, sorted
int nextPrime[MAX_PRIME]      // nextPrime[i] is the index of the next prime >= i

where nextPrime[i] is the starting point in the array primes for the first prime > i.

then, to iterate over e.g.   2000 primes from   3456, you would do

int j = nextPrime[3456]
for (i = j; i < j + 2000; i++) {
    int x = prime[i];
    ... do whatever with x ...
}

答案 6 :(得分:1)

  

我需要知道,例如,在1000000000和相同数字减去100000之间的素数。

然后为你感兴趣的那些数字构建一个筛子。计算下面的所有素数都是浪费,除非你想知道999900000以下有多少素数。

这个数字大小的良好数据结构是有点设置的。因为大约21个数字中的一个是素数,它比显式存储数字所需的内存更少,并且它足以快速遍历范围。

编辑:具体来说,在我的笔记本电脑上用Java筛选整个范围需要花一点多时间,筛选最后100000大约30毫秒。

答案 7 :(得分:0)

如果你想要最好的数据结构来快速找到x和y之间的素数(如你的例子中所示),你需要一个二进制索引树

有一个很好的描述here

答案 8 :(得分:0)

这个java applet看起来相当快:Prials表从1到1 000 000 000 000 http://www.walter-fendt.de/m14e/primes.htm(虽然没有来源,但你可能会尝试作者)

答案 9 :(得分:0)

一组数字可能会很好:)

问题可能是生成数组?在这种情况下,创建一个包含数组的对象并填充它(通过生成它们或从素数列表中读取)。完成后,将其序列化为磁盘,以便程序可以在将来快速读取二进制流以加载阵列。

有关如何生成素数组的变体,请参阅此问题:Prime number calculation fun

答案 10 :(得分:0)

根据您的要求,您应该使用Eratosthenes的分段筛。它不需要大量的内存..

查找所有素数到999900000的平方根。(~31,621) 它可以很容易地存储在数组中。

现在,在100000长度的阵列上执行筛分过程。这些素数。

对于大数字而言效率很高。