【问题标题】:Prime Number finding algorithm returns weird values素数查找算法返回奇怪的值
【发布时间】:2020-07-30 05:32:12
【问题描述】:

我开始学习 c++,并且正在应对 Project Euler 挑战,#7 要求您找到给定范围内的所有素数。经过在线研究,我决定尝试使用Sieve of Erastothenes,但是使用我设置的代码,当我要求 2 个素数和 (2, 4, 5, 5) 时,我目前得到奇怪的值,例如 )2, 0)当我输入 5.

#include <iostream>
#include <vector>
#include <math.h>
#include <bits/stdc++.h>

using namespace std;

int main(){

int end_point;
cout << "how many prime numbers would you like to find?\n";
cin >> end_point;

//creates a vector to store all values, that will eventually be whittled down to primes
vector<int> primes = {2};

//adds all numbers between 2 and chosen end point to the vector
for (int i = 3; i <= end_point; i++){

    primes.push_back(i);
}

for (int i = 0; i < end_point; i++){

    //starts at the first value (always 2), and feeds it into the next for loop
    //once the next loop is done, it moves on to the next value in the loop and feeds that in
    primes[i];

    //looks at values in the vector, starting with the next value in the vector
    for (unsigned int j = i+1; j < primes.size(); j++){

        //checks if the value at [j] is divisible by the value at [i]
        //if it is, this deletes it from the vecotr
        //if not, it moves on to the next value in the vector
        if(primes[j] % primes[i] == 0){

            primes.erase (primes.begin() + (j-1));
        }
        else{}
    }

//prints out all of the primes in the specified range
cout << "Primes are: ";
for (unsigned int k = 0; k <= primes.size(); k++){
    cout << primes[k] << ", ";
}
}
}

【问题讨论】:

  • 这里有很多错误,例如您使用end_point 就好像它是您的primes 向量的大小,但事实并非如此。如果您将primes 声明为布尔向量,您会发现这更容易(并且您的代码也将更有效率)。因此,如果 n 已被证明不是素数,则 primes[n] 为假。这种方法意味着您不必调整 primes 向量的大小,这将使您的代码不仅更简单而且更高效。
  • #include &lt;bits/stdc++.h&gt; - 不要永远包含该标题。它是一个内部实现特定的头文件,不打算包含在内,也不能与其他编译器一起使用。另见Why should I not #include <bits/stdc++.h>?
  • 声明primes[i];应该做什么?因为它没有。
  • 对于欧拉计划,我将素数存储在 std::set&lt;long int&gt; 中。 ;-)
  • @MarquisofLorne,我打算让 primes[i] 跟踪我们在向量中的位置,例如,第一次迭代它应该找到 i = 0 处的值,即 2,并且检查 2 的倍数,然后在我迭代时检查 i = 1,即 3。至少,这就是我的意图。导致它什么也不做的错误在哪里?

标签: c++ algorithm primes


【解决方案1】:

您不应该在遍历数组时从数组中移除元素。您可以通过标记来尝试。 例子:

#include <iostream>
#include <vector>
#include <math.h>

using namespace std;

int main() {

    int end_point;
    cout << "how many prime numbers would you like to find?\n";
    cin >> end_point;

    //creates a vector to store all values, that will eventually be whittled down to primes
    vector<int> primes = { 2 };

    //adds all numbers between 2 and chosen end point to the vector
    for (int i = 3; i <= end_point; i++) {

        primes.push_back(i);
    }

    for (int i = 0; i < end_point; i++) {

        //starts at the first value (always 2), and feeds it into the next for loop
        //once the next loop is done, it moves on to the next value in the loop and feeds that in
        int val = primes[i];

        // to ensure the value is not zero
        if (val == 0)
            continue;

        //looks at values in the vector, starting with the next value in the vector
        for (unsigned int j = i + 1; j < primes.size(); j++) {

            //checks if the value at [j] is divisible by the value at [i]
            //if it is, this deletes it from the vecotr
            //if not, it moves on to the next value in the vector
            if (primes[j] > 0 && primes[j] % val == 0) {
                // set the value zero to element of array.
                primes[j] = 0;
            }
        }

        //prints out all of the primes in the specified range
        cout << "Primes are: ";
        for (unsigned int k = 0; k <= primes.size(); k++) {
            if (primes[k] > 0) // output the value which greater then zero.
                cout << primes[k] << ", ";
        }
    }

    return 0;
}

【讨论】:

    【解决方案2】:
    1. 您删除了错误的元素。没错:

      primes.erase(primes.begin() + j);

    2. 你的最后一个循环在错误的地方。将其从之前的“for 循环”中取出。你去最后一个元素。应该是:

      k

    不是

    k <= primes.size();
    

    === 现在可以正常使用了===

    #include <iostream>
    #include <vector>
    #include <math.h>
    
    using namespace std;
    
    int main() {
    
        int end_point;
        cout << "how many prime numbers would you like to find?\n";
        cin >> end_point;
    
        vector<int> primes = { 2 };
    
        for (int i = 3; i <= end_point; i++) {
            primes.push_back(i);
        }
    
        for (int i = 0; i < end_point; i++) {
            for (unsigned int j = i + 1; j < primes.size(); j++) {
                if (primes[j] % primes[i] == 0) {
                    primes.erase(primes.begin() + j);
                }
                else {}
            }
        }
        cout << "Primes are: ";
        for (unsigned int k = 0; k < primes.size(); k++) {
            cout << primes[k] << ", ";
        }
        return 0;
    }
    

    【讨论】:

    • for 循环在删除元素时可能不应该增加 j
    • 谢谢!我什至没有意识到最后一个循环在另一个循环内。这可能就是为什么我遇到了一堆麻烦,只是首先让它输出。 @AlanBirtles,您可能是对的,但在这种情况下,我认为它可以解决,因为 j 必须检查所有其他数字以开始,因此在删除一个值后跳过一个值,最终不会造成任何伤害我可以告诉。
    【解决方案3】:

    您可以检查从 2 到该数字的 sqrt 的素数。这将省略重复和额外的检查。

    #include <iostream>
    #include <math.h>
    #include <vector>
    
    using namespace std;
    
    vector<int> getPrimes(int start, int end){
        if( start <0 || end < 0 || end < start ){
            return {};
        }
        
        int max = 0;
        bool isPrime = true;
        vector<int> prims = {};
        
        
        for( int i = start ; i <= end ; i++ ){
            max = sqrt(i);
            isPrime = true;
            for(int j = 2 ; j <= max ; j++ ){
                if( i % j == 0 ){
                    isPrime = false;
                    break;
                }
            }
            
            if(isPrime){
                prims.push_back(i);
            }
        }
        
        return prims;
    }
    
    int main()
    {
        
        
        vector<int> prims = getPrimes(0,100);
        
    
        
        for(int n : prims) {
            cout << n << '\n';
        }
        
        return 0;
      
    }
    
    

    Sqrt 原因:

    假设你想知道 17 是否是质数。最简单的方法是从 0 循环到 17 以检查其倍数。但它不需要这样做。 17 的 sqrt 几乎是 4。所以你检查倍数,直到数字 4。下一个数字是 5。从 5 到 17,其结果小于 17 的所有倍数是从 4 到 0。因为 5 * 5 是25 .甚至 5 * 4 也是 20。所以所有的倍数都是重复的。 现在您可以检查从 2 到该数字平方根的倍数,以确定该数字是否为质数

    【讨论】:

    • 这是正确的代码(我认为),但它不是 OP 想要的 Erastothenes 算法的筛子。
    • 是的。不是,但我认为他只是想要一个算法来做到这一点。
    • 任何人都可以在互联网上找到 some 算法的实现。真正有帮助的是发现和解释 OP 错误并帮助修复它们,因此 OP 可以更好地理解语言和算法。提供现成的解决方案往往会导致人们只是复制粘贴代码,他们会遇到各种各样的问题,因为他们不理解他们正在使用的代码。
    • 如果每个人都可以在互联网上找到一些算法,那么就永远不需要编写这些代码了。 OP 刚刚说 `经过在线研究,我决定尝试使用 Erastothenes 筛法`,因此他需要有关该算法或新算法的帮助。如果他需要有关算法的帮助,我会在这里回答有关该算法的问题,只要他想了解它而不仅仅是复制和粘贴。这取决于那个人及其目标。但是,如果需要,其他所有人也可以使用这些算法。祝你好运
    • @churill,你说得对,如果我真的看的话,我真的可以在互联网上找到所有这些,但这有点违背了目的,我并没有真正看对于最佳解决方案或任何东西,我刚刚找到了筛算法,认为它很有趣,并决定尝试一下。我绝对应该指定我更喜欢只使用那个算法,而且它只是为了学习。感谢大家的帮助!还有,为什么你只需要检查到终点的 sqrt?
    猜你喜欢
    • 2012-06-21
    • 1970-01-01
    • 2018-07-10
    • 2020-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-09
    相关资源
    最近更新 更多