【问题标题】:Print prime numbers less than 100 [duplicate]打印小于 100 的素数 [重复]
【发布时间】:2011-12-20 13:49:29
【问题描述】:

可能重复:
Which is the fastest algorithm to find prime numbers?

有什么办法可以让这个更优化..

#include <vector>
    int main()
    {
        std::vector<int> primes;
        primes.push_back(2);
        for(int i=3; i < 100; i++)
        {
            bool prime=true;
            for(int j=0;j<primes.size() && primes[j]*primes[j] <= i;j++)
            {
                if(i % primes[j] == 0)
                {
                    prime=false;
                    break;
                }
            }
            if(prime) 
            {
                primes.push_back(i);
                cout << i << " ";
            }
        }

        return 0;
    }

【问题讨论】:

  • 您可以将循环的 i++ 部分更改为 i +=2,因为我们知道所有偶数无论如何都不会是素数
  • 需要加作业标签吗?
  • 已经有很多关于这个主题的问题了。

标签: c++


【解决方案1】:

是的,埃拉托色尼筛法是最佳选择(如果您需要超过 100 个数字,this 是最佳实施方式)。这是我的实现:

#include <vector>
#include <iostream>
#include <cmath>
using namespace std;

vector<int> sieve(int n){
    vector<bool> prime(n+1,true);
    vector<int> res;
    prime[0]=prime[1]=false;
    int m = (int)sqrt(n);
    for(int i=2; i<=m; i++){
        if(prime[i])
            for(int k=i*i; k<=n; k+=i)
                prime[k]=false;
    }
    for(int i=0; i<n ;i++)
        if(prime[i])
            res.push_back(i);
    return res;
}

int main(){
    vector<int> primes = sieve(100);
    for(int i=0; i<primes.size() ;i++){
        if(i) cout<<", ";
        if(primes[i]) cout<<i;
    }
    cout<<endl;
}

【讨论】:

  • 一个有趣的问题是使用vector&lt;bool&gt; 是否比使用vector&lt;char&gt; 更快(0 和1 分别代表false 和true)。 vector&lt;bool&gt; 读取或写入任何单个值当然需要付出很多额外的努力,但 vector&lt;char&gt; 将占用 8 倍以上的内存,降低了局部性,并导致更多的缓存未命中。
  • 在 C++ 中 bool 和 chars 使用 8 位,但 bool 并不使用所有这些。
  • 在 C++ 中,boolchar 的大小由实现定义。我知道今天的机器 char 是 8、9 或 32 位,bool 可以是单个 char,或者更多——肯定有一些系统的大小与 @987654334 相同@(4 或 6 个字节,在我知道的两个平台上是这种情况)。这些都与这里无关,因为std::vector&lt;bool&gt; 专门用于每个布尔值仅使用 1 位。我的评论从何而来。
  • 很有趣,因为这两篇文章中的答案绕开了这个问题。 bool 至少有 char 大小的原因是因为标准不允许 sizeof(bool) 小于 1,并且要求 sizeof(char) 为 1。寻址问题是这样做的动机, 有点;如果标准允许的话,当然可以生成寻址位的代码,但效率低下,更糟的是,sizeof 和指针算法会产生无穷无尽的问题。
【解决方案2】:
int main(int argc, char *argv[]) {
    cout << "2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ";
}

:-)

更重要的是,您可以通过缓存 primes[j] * primes[j] 来避免重复对素数求平方并节省乘法。

【讨论】:

  • 101呢,你忘了!
  • +1:给定范围的好答案。
  • 哈哈,我喜欢这个回复。它确实是输出所有低于 100 的素数的最快方法
  • 但他要求打印 100 个素数,而不是素数
  • OP 的代码与标题相矛盾。除非代码/逻辑错误,否则 OP 希望生成 100 以下的素数(?)。
【解决方案3】:

是的。正如 Marion 所建议的,您可以使用Sieve of Eratosthenes,但您应该了解详细信息。您编写的代码表面上看起来像筛子,但事实并非如此。它叫做试除法,它的algorithmic complexity与筛子不同。

筛子对每个素数 p 进行一次传递,需要 Theta(n/p) 时间。这导致总复杂度为O(n log log n)。 IIRC 的证明有点复杂,涉及到prime number theorem

您的算法对每个素数 p 执行 pi(sqrt(p)) 除法,对非素数执行少量除法。 (其中piprime-counting function)。不幸的是,我想不出总的复杂性。

简而言之,您应该更改代码以使用数组并标记所有非素数。 This article 解决了函数式编程语言中的相同主题。

【讨论】:

  • 是的。我显然没有考虑清楚。
【解决方案4】:
  1. 不要做primes[j]*primes[j] &lt;= i只检查primes[j] &lt;= 7
  2. 使用i+=2

【讨论】:

  • 考虑到primes[3]==7,写j &lt;=3 就更简单了。 (primes[j] &lt; 11 会更明显)。
【解决方案5】:

是的,将i++ 更改为i+=2,它的运行速度会提高一倍。

【讨论】:

  • 不,它不会...只是微优化
  • 如果你只测试一半的数字,为什么不能让它快两倍?
  • 因为您针对第一个素数(即 2)测试它,立即退出循环。
  • 是的,你会提前停止搜索
  • 或者更好,除了 2 和 3,所有素数的形式都是 6n ± 1。
【解决方案6】:

Sieve of Eratosthenes 是一个很棒的算法,可以生成一个特定数量的素数(这不是你的标题所说的,而是你的代码所暗示的)。

【讨论】:

  • 我不认为 Sieve 算法在 [1..100] 范围内的数字情况下比 nave 算法效果更好
  • @SaeedAmiri 你为什么不这么认为?
  • @Paŭlo Ebermann,因为在这个范围内有很多数字可以被 2,3,5,7 整除,你会多次检查它们,但是通过简单的算法你会跳过这种类型的检查,因为在 nave 算法中只有 3,5,7 应该检查,没有太多性能问题实际上最多检查 150 次,但是在 sieve 算法中我不知道应该有多少检查但应该是超过150,只是猜测不难计算。
  • @SaeedAmiri 在更大的范围(1/2、1/3、1/5、1/7)中可被 2、3、5、7 整除的数字的比例相同,所以我不'不明白为什么筛子应该在那里变得更快。
  • @Paŭlo Eberman 因为在更大的范围内,更大的素数将包含在 nave 算法中。事实上sqrt nlog n 将不在这里有意义。 (无症状功能在不小的范围内可以看到)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-09
  • 1970-01-01
  • 1970-01-01
  • 2019-11-16
  • 2021-05-03
  • 2012-06-09
  • 2016-02-16
相关资源
最近更新 更多