Eratosthenes的C ++ Sieve发现3个太多的素数

时间:2013-01-27 21:10:20

标签: c++ linked-list sieve-of-eratosthenes

我有一个编程任务,用C ++编写一个程序,找到所有小于 n (用户输入)的素数。任务的一半涉及Eratosthenes的Sieve。我的代码正常工作(读取:分配完成),但在编辑输出之前,它无条件地打印出 n-3 n-2 n-1 作为素数,即使它们不是素数。我不确定为什么会这样。我很欣赏一些关于为什么程序按照它的方式行事的反馈和想法。这是未经改动的代码:

请注意我使用ListNode类和LinkedList类,它们都是完全正常的。编辑:部分主要添加;注意 for 循环中的第二项是 size-3 。如果它留在 size ,程序将输出3个额外的非素数。

int main()
{
    for(int i = 0; i<my_list.size()-3; i++)
    {
        if(marked[i]==true)
            cout<<my_list[i]<<"\n";
    }
}

void eratosthenes(int item)
{
   bool run=true;
   int p=2, count=0;

   for(int i=2; i<=item; i++)
   {
      my_list.append(i);    // Entire list is filled with integers from 2 to n
      marked.append(true);  // Entire list is filled with true entries
   }

   while(run==true&&(2*p)<item)
   {
      count = 0;
      int i = (2*p);

      do {
         marked[i-2]=false;       // marked values are false and not prime
         i+=p;
      } while(i<item-2);

      for(int i=0; i<item-2; i++) // i starts at 0  and increments by 1 
      {                           // each time through the loop
         if(my_list[i]>p)
         {
            if(marked[i]==true)   // If a value stored in a node is true  
            {                     //   (prime), it becomes the new p.
               p=my_list[i];      //   The loop is then broken. 
               break;
            }
         }
      }
      for(int j=1; j<item-2; j++)
      {
         if(marked[j]==false)
         {
            count=1;
         }
      }
      if(count==0)
         run=false;
   }

3 个答案:

答案 0 :(得分:1)

完整方法

    void Eratosthenes(int upperBound)
    {
        bool Prime[upperBound];
        for(int i = 0;i<upperBound;i++)
         Prime[i]=true;

        for (int i = 2; i <= sqrt(upperBound); i++) 
         {
             if (Prime[i]) 
             {
                for (int j = i * 2; j < upperBound; j += i) 
                    Prime[j] = false;

              }
         }
         for(int i=2;i<upperBound;i++)
         {
                 if(Prime[i]==true)
                 cout<<i<<" ";
          }
    }

答案 1 :(得分:0)

为什么不从索引2开始简单地使用布尔数组,当你打印结果时,你将打印值为true的索引

答案 2 :(得分:0)

从你的代码:

  do{
     marked[i-2]=false;//marked values are false and not prime
     i+=p;
  }while(i<item-2);

这个循环负责遍历所有数字i,它们是素数p的整数倍,并且标记它们不是素数,据我所知。你为什么要在i < item - 2的条件下停下来?如果imy_listmarked列表的索引,那么这样会很好,但在这种情况下,它不是;这是你标记不是素数的实际数字。我怀疑这就是为什么你的数字接近你的极限(item)被标记为素数的原因 - 你的循环会在i到达这些数字之前退出!

顺便说一句,您可以将其作为for循环来执行,这样更容易阅读。 for循环的含义是“遍历集合中的每个元素”(无论是连续的整数,还是每个n个整数,还是数组/列表/双端队列中的元素等),因此读取代码的程序员会立即知道不必从你的while循环中弄明白。

// mark every multiple of the current prime as not prime
for(int i = 2*p; i < item - 2; i += p)
{
    marked[i-2] = false;
}

(这与原始代码相同,未应用任何修正)。


一些改进算法/代码的一般性评论:

尝试使用更具描述性的变量名称。你使用i两次来表示不同的东西是令人困惑的,一般来说,单个字母对变量所代表的含义并不多(虽然有时候它们就足够了,例如for {{1} }是列表/数组的索引。

此外,您的列表循环比您需要的要多得多。 Eratosthenes算法需要的最小筛子是两个嵌套for循环(不包括将列表/数组初始化为所有i)。

你做的工作超出必要的一个例子就是你从索引0开始循环以找到要使用的下一个true - 而不是仅仅记住当前p的位置并从那里开始。在这种情况下,您甚至不需要检查p,因为您知道自己已经超越它了。此外,你的最后一个循环可以提前my_list[i] > p并避免在找到非素数之后继续(我不确定它是什么意思)。

Nikola Mitev的第二个答案是更有效,更易读的筛子实施(但用break;取代sqrt(upperBound)使其正常工作; upperBound/2的原因应该是upperBound/2从Sieve的工作方式中可以很清楚),尽管他并没有真正给出很多评论或解释。第一个循环是“遍历每个数字直到upperBound”;在它内部,“如果当前数字是素数,则通过该素数的所有倍数并将它们标记为非素数”。在内循环执行之后,外循环继续,经过下一个数字 - 无需从头开始,或者甚至输出另一个for循环,以找到下一个素数。

编辑:sqrt(upperBound)是正确的。我没有仔细考虑它。