如何在 Sieve_of_Eratosthenes 中使用更少的内存
How to use less memory in Sieve_of_Eratosthenes
我正在一个类似 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
。
有什么方法可以减少这段代码的内存使用量吗?
这是埃拉托色尼筛法的内存优化实现。基本思想是,你只需要存储奇数的状态。其余部分与正常实施类似。
#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;
}
一些建议:
- 使用仅表示奇数的位数组
- 将问题分解成多个部分,以便部分筛选使用更少的内存
@Kim Walish 在这里有一个快速的 C++ 版本:
https://github.com/kimwalisch/primesieve/wiki/Segmented-sieve-of-Eratosthenes
您仍然可以通过始终将段大小限制为 L1 缓存大小,并将 IsPrime 数组更改为奇数位数组来使其使用更少的内存。
我正在一个类似 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
。
有什么方法可以减少这段代码的内存使用量吗?
这是埃拉托色尼筛法的内存优化实现。基本思想是,你只需要存储奇数的状态。其余部分与正常实施类似。
#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;
}
一些建议:
- 使用仅表示奇数的位数组
- 将问题分解成多个部分,以便部分筛选使用更少的内存
@Kim Walish 在这里有一个快速的 C++ 版本:
https://github.com/kimwalisch/primesieve/wiki/Segmented-sieve-of-Eratosthenes
您仍然可以通过始终将段大小限制为 L1 缓存大小,并将 IsPrime 数组更改为奇数位数组来使其使用更少的内存。