如何在 Sieve_of_Eratosthenes 中使用更少的内存
Posted
技术标签:
【中文标题】如何在 Sieve_of_Eratosthenes 中使用更少的内存【英文标题】:How to use less memory in Sieve_of_Eratosthenes 【发布时间】:2019-08-17 02:02:08 【问题描述】:我正在一个类似 leetcode 的平台上编码。有一个任务:计算低于给定界限的素数。
我使用了算法:https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
我从这里复制代码:https://www.geeksforgeeks.org/sieve-of-eratosthenes/,除了我让false
代表isPrime
以避免使用memset
。这是我的代码:
void SieveOfEratosthenes(int n)
bool *prime = new bool[n+1](); // initialized by false by default
for (int p=2; p*p<=n; p++)
if (prime[p] == false)
for (int i=p*p; i<=n; i += p)
prime[i] = true;
for (int p=2; p<=n; p++)
if (prime[p])
cout << p << " ";
但是,当我执行它时,平台告诉我在100 000 000
作为输入的情况下我使用了太多的内存。
我检查了sizeof(bool)
等于1
。
有什么方法可以减少这段代码的内存消耗吗?
【问题讨论】:
codereview.stackexchange.com/questions/112227/… @JamesKPolk 好吧,我想我在那篇文章中已经使用了所有方法。std::vector<bool>
每个元素使用 1 个 bit,因此使用 bool 数组的 1/8 存储空间。
您应该尝试实施 Eratosthenes 的分段筛吗?它的主要目标是减少内存使用。
@JosephWood ... 从而大大加快了速度,让内存适合缓存。 :)
【参考方案1】:
几个建议:
使用仅表示奇数的位数组 将问题分成几段,这样部分筛子使用的内存要少得多@Kim Walish 在这里有一个快速的 C++ 版本:
https://github.com/kimwalisch/primesieve/wiki/Segmented-sieve-of-Eratosthenes
您可以通过始终将段大小限制为 L1 缓存大小以及将 IsPrime 数组更改为奇数位数组来使其使用更少的内存。
【讨论】:
【参考方案2】:这是一个内存优化的 Eratosthenes 筛子的实现。基本思想是,您只需要存储奇数的状态。其余部分与正常实现类似。
#include <iostream>
class Solution
public:
int countPrimes(int n)
//if(n <= 1) return 0; // including n
if(n <= 2) return 0; // number of primes less than 0 / 1 / 2 is 0
const int MAXN = 1500000 + 5; // adjust MAXN accordingly
// finding prime from 1 up to N
int status[(MAXN >> 1) + 1]; // we need space for only the odd numbers
// works well up to 1.5 * 10 ^ 6, for numbers larger than that, you need to adjust the second operand accordingly
int prime[115000 + 1000]; // prime number distribution , pi(x) = x/ (ln(x) - 1) , adjust this according to MAXN
// If status[i] = 0 -> i is prime
// If status[i] = 1 -> i is not prime
for(int i = 1 ; i <= (n >> 1) ; ++i) status[i] = 0; // for every i , 2 * i + 1 is the odd number, marking it as prime
int sqrtN = static_cast <int> ((sqrt (static_cast <double> (n))));
// computing sqrt(N) only once because it is costly computing it inside a loop
// only accounting the odd numbers and their multiples
for(int i = 3 ; i <= sqrtN ; i += 2)
if(status[i >> 1] == 0)
// if this is still a prime then discard its multiples
// first multiple that needs to be discarded starts at i * i
// all the previous ones have already been discarded
for(int j = i * i ; j <= n ; j += (i + i))
//printf("Marking %d as not prime\n",j);
status[j >> 1] = 1;
int counter = 0;
prime[counter++] = 2;
for(int i = 3 ; i <= n ; i += 2)
if(status[i >> 1] == 0)
prime[counter++] = i;
if( (n & 1) && !status[n >> 1]) counter--; // if n is prime, discard n
std::cout << "Number of primes less than " << n << " is " << counter << "\n";
for(int i = 0 ; i < counter; ++i)
std::cout << prime[i];
if(i != counter - 1) std::cout << "\n";
std::cout << "\n";
return counter;
;
int main(int argc, char const *argv[])
Solution solution;
int n; std::cin >> n;
solution.countPrimes(n);
return 0;
【讨论】:
以上是关于如何在 Sieve_of_Eratosthenes 中使用更少的内存的主要内容,如果未能解决你的问题,请参考以下文章