Eratosthenes算法的筛选

时间:2009-12-23 19:31:43

标签: c++ algorithm

我目前正在阅读“编程:使用C ++的原则和实践”,在第4章中有一个练习:

  

我需要制作一个程序,使用Sieve of Eratosthenes算法计算1到100之间的素数。

这是我提出的计划:

#include <vector>
#include <iostream>

using namespace std;

//finds prime numbers using Sieve of Eratosthenes algorithm
vector<int> calc_primes(const int max);

int main()
{
    const int max = 100;

    vector<int> primes = calc_primes(max);

    for(int i = 0; i < primes.size(); i++)
    {
        if(primes[i] != 0)
            cout<<primes[i]<<endl;
    }

    return 0;
}

vector<int> calc_primes(const int max)
{
    vector<int> primes;

    for(int i = 2; i < max; i++)
    {
        primes.push_back(i);
    }

    for(int i = 0; i < primes.size(); i++)
    {
        if(!(primes[i] % 2) && primes[i] != 2)
             primes[i] = 0;
        else if(!(primes[i] % 3) && primes[i] != 3)
             primes[i]= 0;
        else if(!(primes[i] % 5) && primes[i] != 5)
             primes[i]= 0;
        else if(!(primes[i] % 7) && primes[i] != 7)
             primes[i]= 0;
    }   

    return primes;
}

不是最好的或最快的,但我仍然在本书的早期,并且对C ++知之甚少。

现在出现问题,直到max不大于500所有值都会在控制台上打印,如果max > 500并非所有内容都被打印出来。

我做错了吗?

P.S。:任何建设性的批评都会受到高度赞赏。

13 个答案:

答案 0 :(得分:5)

将筛子视为一组。
按顺序浏览设置。对于thesive中的每个值,删除所有可被它们分割的数字。

#include <set>
#include <algorithm>
#include <iterator>
#include <iostream>


typedef std::set<int>   Sieve;

int main()
{
    static int const max = 100;

    Sieve   sieve;

    for(int loop=2;loop < max;++loop)
    {
        sieve.insert(loop);
    }


    // A set is ordered.
    // So going from beginning to end will give all the values in order.
    for(Sieve::iterator loop = sieve.begin();loop != sieve.end();++loop)
    {
        // prime is the next item in the set
        // It has not been deleted so it must be prime.
        int             prime   = *loop;

        // deleter will iterate over all the items from
        // here to the end of the sieve and remove any
        // that are divisable be this prime.
        Sieve::iterator deleter = loop;
        ++deleter;

        while(deleter != sieve.end())
        {
            if (((*deleter) % prime) == 0)
            {
                // If it is exactly divasable then it is not a prime
                // So delete it from the sieve. Note the use of post
                // increment here. This increments deleter but returns
                // the old value to be used in the erase method.
                sieve.erase(deleter++);
            }
            else
            {
                // Otherwise just increment the deleter.
                ++deleter;
            }
        }
    }

    // This copies all the values left in the sieve to the output.
    // i.e. It prints all the primes.
    std::copy(sieve.begin(),sieve.end(),std::ostream_iterator<int>(std::cout,"\n"));

}

答案 1 :(得分:5)

我不知道为什么你没有得到所有输出,因为看起来你应该得到一切。你缺少什么输出?

筛子实施错误。像

这样的东西
vector<int> sieve;
vector<int> primes;

for (int i = 1; i < max + 1; ++i)
   sieve.push_back(i);   // you'll learn more efficient ways to handle this later
sieve[0]=0;
for (int i = 2; i < max + 1; ++i) {   // there are lots of brace styles, this is mine
   if (sieve[i-1] != 0) {
      primes.push_back(sieve[i-1]);
      for (int j = 2 * sieve[i-1]; j < max + 1; j += sieve[i-1]) {
          sieve[j-1] = 0;
      }
   }
}

将实施筛子。 (上面的代码写在我的头顶;不能保证工作甚至编译。我认为第4章末尾没有涉及任何内容。)

像往常一样返回primes,然后打印出全部内容。

答案 2 :(得分:4)

来自Algorithms and Data Structures

void runEratosthenesSieve(int upperBound) {
      int upperBoundSquareRoot = (int)sqrt((double)upperBound);
      bool *isComposite = new bool[upperBound + 1];
      memset(isComposite, 0, sizeof(bool) * (upperBound + 1));
      for (int m = 2; m <= upperBoundSquareRoot; m++) {
            if (!isComposite[m]) {
                  cout << m << " ";
                  for (int k = m * m; k <= upperBound; k += m)
                        isComposite[k] = true;
            }
      }
      for (int m = upperBoundSquareRoot; m <= upperBound; m++)
            if (!isComposite[m])
                  cout << m << " ";
      delete [] isComposite;
}

答案 3 :(得分:4)

有趣的是,似乎没有人回答你关于输出问题的问题。我没有在代码中看到任何应该影响输出的内容,具体取决于max。

的值

对于它的价值,在我的Mac上,我得到了所有的输出。当然这是错误的,因为算法不正确,但我确实得到了所有输出。您没有提到正在运行的平台,如果您继续遇到输出问题,这可能很有用。


这是您的代码版本,经过最低限度的修改,可以遵循实际的Sieve算法。

#include <vector>
#include <iostream>

using namespace std;

//finds prime numbers using Sieve of Eratosthenes algorithm
vector<int> calc_primes(const int max);

int main()
{
    const int max = 100;

    vector<int> primes = calc_primes(max);

    for(int i = 0; i < primes.size(); i++)
    {
        if(primes[i] != 0)
            cout<<primes[i]<<endl;
    }

    return 0;
}

vector<int> calc_primes(const int max)
{
    vector<int> primes;

    // fill vector with candidates
    for(int i = 2; i < max; i++)
    {
        primes.push_back(i);
    }

    // for each value in the vector...
    for(int i = 0; i < primes.size(); i++)
    {
        //get the value
        int v = primes[i];

        if (v!=0) {
            //remove all multiples of the value
            int x = i+v;
            while(x < primes.size()) {
                primes[x]=0;
                x = x+v;
            }
        }
    }
    return primes;
}

答案 4 :(得分:2)

在下面的代码片段中,数字会在插入vector之前进行过滤。除数来自向量。

我也通过引用传递矢量。这意味着巨大的向量将不会从函数复制到调用者。 (大块内存需要很长时间才能复制)

vector<unsigned int> primes;

void calc_primes(vector<unsigned int>& primes, const unsigned int MAX)
{
    // If MAX is less than 2, return an empty vector
    // because 2 is the first prime and can't be placed in the vector.
    if (MAX < 2)
    {
         return;
    }

    // 2 is the initial and unusual prime, so enter it without calculations.
    primes.push_back(2);
    for (unsigned int number = 3; number < MAX; number += 2)
    {
        bool is_prime = true;
        for (unsigned int index = 0; index < primes.size(); ++index)
        {
            if ((number % primes[k]) == 0)
            {
                is_prime = false;
                break;
            }
        }

        if (is_prime)
        {
            primes.push_back(number);
        }
    }    
}

这不是最有效的算法,但它遵循 Sieve 算法。

答案 5 :(得分:1)

下面是我的版本,它基本上使用bool的位向量,然后通过奇数和快速添加找到倍数设置为false。最后构造一个向量并将其返回给素值的客户端。

std::vector<int>  getSieveOfEratosthenes ( int max )
{
  std::vector<bool> primes(max, true);
  int sz = primes.size();

  for ( int i = 3; i < sz ; i+=2 )
    if ( primes[i] ) 
      for ( int j = i * i; j < sz; j+=i)
        primes[j] = false;

  std::vector<int> ret;
  ret.reserve(primes.size());
  ret.push_back(2);

  for ( int i = 3; i < sz; i+=2 )
    if ( primes[i] )
      ret.push_back(i);

  return ret;
}

答案 6 :(得分:1)

以下是使用bool类型的简明扼要解释的实现:

#include <iostream>
#include <cmath>

void find_primes(bool[], unsigned int);
void print_primes(bool [], unsigned int);

//=========================================================================
int main() 
{
    const unsigned int max = 100;
    bool sieve[max];

    find_primes(sieve, max);

    print_primes(sieve, max);
}
//=========================================================================

/*
    Function: find_primes()
    Use: find_primes(bool_array, size_of_array);

    It marks all the prime numbers till the
    number: size_of_array, in the form of the
    indexes of the array with value: true.

    It implemenets the Sieve of Eratosthenes,
    consisted of:

    a loop through the first "sqrt(size_of_array)"
    numbers starting from the first prime (2).

    a loop through all the indexes < size_of_array,
    marking the ones satisfying the relation i^2 + n * i
    as false, i.e. composite numbers, where i - known prime 
    number starting from 2.
*/
void find_primes(bool sieve[], unsigned int size)
{
    // by definition 0 and 1 are not prime numbers
    sieve[0] = false;
    sieve[1] = false;

    // all numbers <= max are potential candidates for primes
    for (unsigned int i = 2; i <= size; ++i)
    {
        sieve[i] = true;
    }

    // loop through the first prime numbers < sqrt(max) (suggested by the algorithm)
    unsigned int first_prime = 2;
    for (unsigned int i = first_prime; i <= std::sqrt(double(size)); ++i)
    {
        // find multiples of primes till < max
        if (sieve[i] = true)
        {
            // mark as composite: i^2 + n * i 
            for (unsigned int j = i * i; j <= size; j += i)
            {
                sieve[j] = false;
            }
        }
    }
}

/*
    Function: print_primes()
    Use: print_primes(bool_array, size_of_array);

    It prints all the prime numbers, 
    i.e. the indexes with value: true.
*/
void print_primes(bool sieve[], unsigned int size)
{
    // all the indexes of the array marked as true are primes
    for (unsigned int i = 0; i <= size; ++i)
    {
        if (sieve[i] == true) 
        {
            std::cout << i <<" ";
        }
    }
}

覆盖数组案例。 std::vector实现将包括微小的更改,例如将函数减少到一个参数,通过引用传递向量,循环将使用向量size()成员函数而不是简化参数。

答案 7 :(得分:0)

这是我实施的Eratosthenes Sieve算法的更高效版本。

#include <iostream>
#include <cmath>
#include <set>

using namespace std;

void sieve(int n){
    set<int> primes;
    primes.insert(2);
    for(int i=3; i<=n ; i+=2){
        primes.insert(i);
    }       

    int p=*primes.begin();
    cout<<p<<"\n";
    primes.erase(p);

    int maxRoot = sqrt(*(primes.rbegin()));

    while(primes.size()>0){
        if(p>maxRoot){
            while(primes.size()>0){
                p=*primes.begin();
                cout<<p<<"\n";
                primes.erase(p);        
            }
            break;
        }

        int i=p*p;  
        int temp = (*(primes.rbegin()));
        while(i<=temp){
            primes.erase(i);
            i+=p;
            i+=p;
        }
        p=*primes.begin();
        cout<<p<<"\n";
        primes.erase(p);
    }
}

int main(){
    int n;
    n = 1000000;
    sieve(n);                
    return 0;
}

答案 8 :(得分:0)

这是我的实现,不确定100%是否正确: http://pastebin.com/M2R2J72d

#include<iostream>
#include <stdlib.h> 

using namespace std;
void listPrimes(int x);

int main() {

    listPrimes(5000);
}

void listPrimes(int x) {
    bool *not_prime = new bool[x];
    unsigned j = 0, i = 0;

    for (i = 0; i <= x; i++) {
        if (i < 2) {
            not_prime[i] = true;
        } else if (i % 2 == 0 && i != 2) {
            not_prime[i] = true;
        }
    }

    while (j <= x) {
        for (i = j; i <= x; i++) {
            if (!not_prime[i]) {
                j = i;
                break;
            }
        }
        for (i = (j * 2); i <= x; i += j) {
            not_prime[i] = true;
        }
        j++;
    }

    for ( i = 0; i <= x; i++) {
        if (!not_prime[i])
            cout << i << ' ';
    }

    return;
}

答案 9 :(得分:0)

我现在正在读同一本书。我已经提出了以下算法实现。

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
inline void keep_window_open() { char ch; cin>>ch; }

int main ()
{
    int max_no = 100;

    vector <int> numbers (max_no - 1);
    iota(numbers.begin(), numbers.end(), 2);

    for (unsigned int ind = 0; ind < numbers.size(); ++ind)
    {
        for (unsigned int index = ind+1; index < numbers.size(); ++index)
        {
            if (numbers[index] % numbers[ind] == 0)
            {
                numbers.erase(numbers.begin() + index);
            }
        }
    }
    cout << "The primes are\n";
    for (int primes: numbers)
    {
        cout << primes << '\n';
    }
}

答案 10 :(得分:0)

这是执行此操作的经典方法,

int main()
{
    int max = 500;
    vector<int> array(max); // vector of max numbers, initialized to default value 0

    for (int i = 2; i < array.size(); ++ i) // loop for rang of numbers from 2 to max
    {
        // initialize j as a composite number; increment in consecutive composite numbers
        for (int j = i * i; j < array.size(); j +=i)
            array[j] = 1;  // assign j to array[index] with value 1
    }

    for (int i = 2; i < array.size(); ++ i) // loop for rang of numbers from 2 to max
        if (array[i] == 0)  // array[index] with value 0 is a prime number
        cout << i << '\n';  // get array[index] with value 0

    return 0;
}

答案 11 :(得分:0)

我想我参加这个聚会很晚,但是我和你读的是同一本书,这是想出的解决方案!随意提出建议(您或任何人!),因为我们在这里看到的是我们中的一些人提取了该操作才能知道某个数字是否是某个函数的另一个数。

#include "../../std_lib_facilities.h"

bool numIsMultipleOf(int n, int m) {
  return n%m == 0;
}

int main() {
  vector<int> rawCollection = {};
  vector<int> numsToCheck = {2,3,5,7};

  // Prepare raw collection
  for (int i=2;i<=100;++i) {
    rawCollection.push_back(i);
  }

  // Check multiples
  for (int m: numsToCheck) {
    vector<int> _temp = {};

    for (int n: rawCollection) {
      if (!numIsMultipleOf(n,m)||n==m) _temp.push_back(n);
    }
    rawCollection = _temp;
  }

  for (int p: rawCollection) {
    cout<<"N("<<p<<")"<<" is prime.\n";
  }

  return 0;
}

答案 12 :(得分:-3)

尝试使用此代码,使用java question bank

对您有用
import java.io.*;

class Sieve

{

    public static void main(String[] args) throws IOException

    {

        int n = 0, primeCounter = 0;

        double sqrt = 0;

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));


        System.out.println(“Enter the n value : ”);

        n = Integer.parseInt(br.readLine());

        sqrt = Math.sqrt(n);

        boolean[] prime = new boolean[n];

        System.out.println(“\n\nThe primes upto ” + n + ” are : ”);

        for (int i = 2; i<n; i++)

        {

            prime[i] = true;

        }

        for (int i = 2; i <= sqrt; i++)

        {

            for (int j = i * 2; j<n; j += i)

            {

                prime[j] = false;

            }

        }

        for (int i = 0; i<prime.length; i++)

        {

            if (prime[i])

            {

                primeCounter++;

                System.out.print(i + ” “);

            }

        }

        prime = new boolean[0];

    }

}