【问题标题】:Error trying to find all the prime numbers from 2 to n using Sieve of Eratosthenes in C++尝试使用 C++ 中的埃拉托色尼筛法查找从 2 到 n 的所有素数时出错
【发布时间】:2016-03-25 20:48:37
【问题描述】:

我需要使用埃拉托色尼筛法找出从 2 到 n 的所有素数。我查看了 Wikipedia(Sieve of Eratosthenes) 以了解 Eratosthenes 的筛子是什么,它给了我这个伪代码:

Input: an integer n > 1

Let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.

for i = 2, 3, 4, ..., not exceeding √n:
  if A[i] is true:
    for j = i2, i2+i, i2+2i, i2+3i, ..., not exceeding n :
      A[j] := false

Output: all i such that A[i] is true.

所以我使用它并将其翻译成 C++。对我来说看起来不错,但我有几个错误。首先,如果我在 n 中输入 2 或 3,它会说:

terminate called after throwing an instance of 'Range_error'
what(): Range_error: 2

此外,每当我输入 100 或其他任何值(4、234、149、22 等)时,它都会接受 n 的输入,并且不执行任何操作。这是我的 C++ 翻译:

#include "std_lib_facilities.h"

int main()
{
/* this program will take in an input 'n' as the maximum value. Then it will calculate
all the prime numbers between 2 and n. It follows the Sieve of Eratosthenes with
the algorithms from Wikipedia's pseudocode translated by me into C++*/

int n;
cin >> n;
vector<string>A;
for(int i = 2; i <= n; ++i) // fills the whole table with "true" from 0 to n-2
    A.push_back("true");

for(int i = 2; i <= sqrt(n); ++i)
{
    i -= 2; // because I built the vector from 0 to n-2, i need to reflect that here.
    if(A[i] == "true")
    {
        for(int j = pow(i, 2); j <= n; j += i)
        {
            A[j] = "false";
        }
    }
}

//print the prime numbers
for(int i = 2; i <= n; ++i)
{
    if(A[i] == "true")
        cout << i << '\n';
}


return 0;
}

【问题讨论】:

  • 你想用那个 i -= 2 做什么?
  • 你也需要在最后一个循环中调整i
  • 单步调试代码时调试器会告诉你什么?
  • 你为什么使用字符串向量而不是布尔向量(或最坏情况下的 int)?比较两个布尔值或整数比比较两个字符串要容易得多。
  • @Martze C++ 向量的索引从 0 到 n 对吗?但我从 2 开始。所以我将 'i' 向下移动 2 以便它与 0 索引相对应

标签: c++


【解决方案1】:

问题在于索引与它们所代表的值不一致,即它们被向下移动了 2。通过执行此操作,它们不再具有相同的数学属性。

基本上,值 3 位于位置 1,值 4 位于位置 2。当您测试除法时,您使用的是位置,因为它们是值。因此,不是测试 4%3==0,而是测试 2%1=0。

为了使您的程序正常工作,您必须删除索引的-2 移位:

int main()
{

int n;
cin >> n;
vector<string>A;
for(int i = 0; i <= n; ++i) // fills the whole table with "true" from 0 to n-2
    A.push_back("true");

for(int i = 2; i <= sqrt(n); ++i)
{
    if(A[i] == "true")
    {
        for(int j = pow(i, 2); j <= n; j += i)
        {
            A[j] = "false";
        }
    }
}

//print the prime numbers
for(int i = 2; i <= n; ++i)
{
    if(A[i] == "true")
        cout << i << '\n';
}


return 0;
}

我同意其他 cmets,您可以使用布尔向量。并直接用正确的大小和值初始化它们:

std::vector<bool> A(n, false);

【讨论】:

  • 当我使用 bool 时,会出现: T& operator[](unsigned int i) // 而不是 return at(i); { if (isize()::operator[](i); } // 在 return 语句中出现错误。这是在头文件 std_lib_facilities.h
【解决方案2】:

在这里你推回n-1元素

vector<string>A;
for(int i = 2; i <= n; ++i) // fills the whole table with "true" from 0 to n-2
    A.push_back("true");

但是在这里你可以从A[2]A[n] 访问你的向量。

//print the prime numbers
for(int i = 2; i <= n; ++i)
{
    if(A[i] == "true")
        cout << i << '\n';
}

AA[0]A[n-2] 的位置有元素。您可以通过以不同方式初始化向量来纠正此缺陷。例如作为

vector<string> A(n+1, "true");

这将创建一个向量An+1 字符串,默认值为“true”,可以通过A[0]A[n] 访问。有了这个你的代码应该运行,即使它有更多的缺陷。但我认为,如果你只是尝试成功实施筛子,然后在互联网上寻找(好的)替代品,你会学到最多。

【讨论】:

    【解决方案3】:

    这很痛苦。为什么要使用字符串数组来存储布尔值,而不是使用布尔值数组?为什么要省略前两个数组元素,迫使您对所有索引进行一些调整?然后您忘记了一半时间,完全破坏了您的代码?至少你应该改变这一行:

    i -= 2; // because I built the vector from 0 to n-2, i need to reflect that here.
    

    到:

    i -= 2; // because I left the first two elements out, I that here.
    // But only here, doing it everywhere is too annoying. 
    

    作为该设计决策的结果,当您执行此行时:

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

    i 实际上是 zero,这意味着 j 将永远保持为零。

    【讨论】:

    • 老兄,每当我使用 bool 来表示向量时,我的 std_lib_facilities.h 中有一个错误
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    • 2011-04-25
    相关资源
    最近更新 更多