如何在 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&lt;bool&gt; 每个元素使用 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 中使用更少的内存的主要内容,如果未能解决你的问题,请参考以下文章

如何在图像中找到明亮区域(以及如何在图像中找到阴影区域)

在QGIS中如何添加天地图的WMTS

如何在表单提交后保留文本(如何在提交后不删除自身?)

如何在异步任务中调用意图?或者如何在 onPostExecute 中开始新的活动?

在 Avkit 中如何使用这三行代码,以及如何将音乐静音”

如何在 JDBC 中启动事务?