有效存储素数

时间:2009-06-23 12:59:13

标签: math data-structures primes factorization

对于库,我需要将第一个素数存储到极限L.此集合必须具有O(1)查找时间(以检查数字是否为素数)并且它必须很容易,给定一个数字,找到下一个素数(假设它小于L)。

鉴于L是固定的,生成清单的Eratostene筛子很好。现在,我使用一个打包的布尔数组来存储列表,该列表只包含3到L(含)之间奇数的条目。这需要(L-2)/ 2位内存。我希望能够在不使用更多内存的情况下静态增加L.

是否存在使用具有相似属性的较少内存的数据结构?或者至少具有恒定的查找时间? (然后可以枚举奇数,直到我们得到一个素数)

(我写的这个语言是Factor但是这个问题在任何内置或易于编程的打包位数组的语言中都是一样的)

9 个答案:

答案 0 :(得分:22)

您可以明确检查更多素数以删除冗余。

目前你只为两个人做这个,通过明确地检查两个可分性,然后只存储奇数,不管它们是否为素数。

对于2和3,你得到剩余的0到5,其中只有1和5不能被2或3整除,并且可以得到素数,所以你可以降到1/3。

对于2,3和5,您可以从30个中获得8个数字,这样可以很好地存储在一个字节中。

更详细地解释了这一点here

答案 1 :(得分:8)

打包位图和滚轮的替代方案 - 但在某些情况下同样有效 - 存储连续素数之间的差异。如果你像往常一样省略数字2,那么所有差异都是均匀的。存储差值/ 2,您可以使用字节大小的变量获得最多2 ^ 40个区域(就在1999066711391之前)。

素数上升2 ^ 32仅需要194 MByte,相比之下,仅有几率的压缩位图需要256 MByte。迭代delta存储的素数比轮式存储快得多,轮式存储包括称为仅赔率位图的模2轮。

对于1999066711391之后的范围,需要更大的单元尺寸或可变长度存储。即使使用非常简单的方案,后者也可以非常有效(例如,在LZ4 - 样式压缩中添加字节<255之前继续添加),因为间隙的频率极低于510 / 2。

为了效率,最好将范围划分为多个部分(页面)并管理它们的B-Tree风格。

对差异进行熵编码(霍夫曼或算术编码)将永久存储要求降低到不到一半,这接近理论最优值,并且优于使用最佳可用封隔器压缩的列表或车轮。

如果数据是未压缩存储的,那么它仍然比二进制或文本数字的文件紧凑得多,数量级或更多。使用B树样式索引,可以根据需要简单地将部分映射到内存中,并以极快的速度迭代它们。

答案 2 :(得分:4)

目前你将2视为特殊情况,然后有一个数组,其中每个奇数都映射到数组中的一个元素(有些奇数是素数)。你可以通过将2和3视为特殊情况来改进这一点,认识到剩余的素数是6n + 1或6n-1(即所有素数p,其中p> 3,p mod 6 = 1或5)。这可以进一步概括 - 见Wikipedia。对于所有素数p> 5,p mod 30 = 1,7,11,13,17,19,23或29.您可以继续使用此操作并以牺牲处理时间为代价减少所需的内存(尽管它仍然是O(1),只是一个较慢的O(1))。

答案 3 :(得分:2)

也许只有素数的trie数据结构才是你想要的。您可以使用整数数字,而不是使用字符作为索引。这方面的实现是Judy-Array s。

尽管如此,它们不符合您的O(1)要求,它们对于类似的键(对于大多数数字部分而言)具有极高的内存效率,并且使用O(m)(m =键)可以快速查找长度)最多。

如果你在预先生成的树中查找素数,你可以走树直到找到它,或者你已经在前面和后面的素数旁边的节点。

答案 4 :(得分:0)

鉴于内存如此便宜,我认为从速度角度来看,你可以做得比现有方案好得多。

如果有更好的解决方案,那么我认为它会利用Prime Number Theorem表明随着L变大,

的限制

π(L)/(L / ln(L))接近1.

也许更好的解决方案是在数据结构中使用类似skip list的自适应打包解决方案。

答案 5 :(得分:0)

某种哈希表怎么样?

你需要一个非常好的哈希函数(类似n mod p,其中p不是任何q最低素数的倍数 - 选择q足够高为了尽量减少碰撞次数。)

答案 6 :(得分:0)

间隔树怎么样? http://www.geeksforgeeks.org/interval-tree/

它可能不是O(1),但它真的很快。像O(log(p(n))),其中p(n)是直到数n的素数。通过这种方式,您所需的内存将仅与素数成比例,大大降低了内存成本。

例如,假设您在p1处找到素数,然后在p2处找到下一个素数, 插入间隔(p1,p2)等等,当您搜索该范围内的任何数字时,它将返回此间隔,您可以返回p2,这将是您案例中的答案。

答案 7 :(得分:-2)

如果你可以找出哪些是Mersenne或其他容易表示的素数,你可以通过使用带有适用数字标志的表示来保存几位。

此外,如何将数字存储为与前一个数字的差异?然后大小不应该快速上升(但查找会很慢)。结合上述方法,您可以存储Mersenne素数和与上一个Mersenne素数的差异。

答案 8 :(得分:-2)