我有一个编程任务,用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;
}
答案 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
的条件下停下来?如果i
是my_list
和marked
列表的索引,那么这样会很好,但在这种情况下,它不是;这是你标记不是素数的实际数字。我怀疑这就是为什么你的数字接近你的极限(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的第二个答案是更有效,更易读的筛子实施(但用),尽管他并没有真正给出很多评论或解释。第一个循环是“遍历每个数字直到upperBound”;在它内部,“如果当前数字是素数,则通过该素数的所有倍数并将它们标记为非素数”。在内循环执行之后,外循环继续,经过下一个数字 - 无需从头开始,或者甚至输出另一个for循环,以找到下一个素数。break;
取代sqrt(upperBound)
使其正常工作; upperBound/2
的原因应该是upperBound/2
从Sieve的工作方式中可以很清楚
编辑:sqrt(upperBound)
是正确的。我没有仔细考虑它。