简体   繁体   English

C ++:Eratosthenes筛子不总是有效

[英]C++: Sieve Of Eratosthenes Not Always Working

I am making a C++ program to find prime numbers using the Sieve of Eratosthenes 我正在制作一个使用Eratosthenes筛子查找素数的C ++程序

Currently I have the following code: 目前,我有以下代码:

C++ C ++

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class is_multiple_of {
    int m_div;
public:
    is_multiple_of(int div) : m_div(div) {}
    bool operator()(int n) { return ((n > m_div) && (0 == n % m_div)); }
};

int main ()
{
    vector<int> v;
    for (int i=2; i<=100; i++) v.push_back(i);

    v.erase( remove_if(v.begin(), v.end(), is_multiple_of(2)), v.end() );
    v.erase( remove_if(v.begin(), v.end(), is_multiple_of(3)), v.end() ); 
    v.erase( remove_if(v.begin(), v.end(), is_multiple_of(5)), v.end() ); 
    v.erase( remove_if(v.begin(), v.end(), is_multiple_of(7)), v.end() ); 

    for (unsigned i=0; i<v.size(); ++i)
        cout << v[i] << " ";


    cout << endl << v.size();
    return 0;
}

which works fine ie it says there are 25 primes between 1 and 100 (which is correct ). 这很好用,即它说1到100之间有25个素数(是正确的 )。 However, if i want to know the first 500 primes for example, it will say there are 118 where in reality there are 95. To correct this issue, I have to add more multiples to remove ie v.erase( remove_if(v.begin(), v.end(), is_multiple_of(11)), v.end() ); 但是,例如,如果我想知道前500个素数,它将说有118个,实际上有95个。要纠正此问题,我必须添加更多倍数以删除即v.erase( remove_if(v.begin(), v.end(), is_multiple_of(11)), v.end() ); and then add more is_multiple_of() 's. 然后添加更多is_multiple_of()

Is there a way to make this more efficient rather than just having it remove more multiples of previously found primes? 有没有一种方法可以使此方法更有效,而不仅仅是消除以前发现的质数的倍数?

Since you want to implement your version of finding the primes, then the following should work (we are using 500) 由于您要实施查找素数的版本,因此以下方法应该起作用(我们正在使用500)

 int stopInt = static_cast<int>(sqrt(500));
 int j = 0;
 for (int i = 0; i < stopInt; ++i, ++j)
     v.erase(remove_if(v.begin(), v.end(), is_multiple_of(v[j])), v.end());

Here is an alternative that "marks" the items by just moving them to the end of the vector: 这是通过仅将项目移到向量的末端来“标记”项目的替代方法:

     vector<int>::iterator sMarked = v.end();
     int stopInt = static_cast<int>(sqrt(500));
     int j = 0;
     for (int i = 0; i < stopInt; ++i, ++j)
         sMarked = remove_if(v.begin(), sMarked, is_multiple_of(v[j]));
     v.erase(sMarked, v.end());

So we're constantly marking the elements by keeping track of the return value of remove_if . 因此,我们通过跟踪remove_if的返回值来不断标记元素。 Then at the end, we do one single vector::erase to remove the multiples. 然后最后,我们执行一个单个vector::erase删除倍数。 This should be more efficient than calling the v_erase constantly in the loop. 这比在循环中不断调用v_erase更为有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM