这个素数生成器是否效率低下C ++?

时间:2008-10-23 20:32:01

标签: c++ performance primes

这被看作是一个有效的素数发生器。在我看来,这是非常有效的。是否使用流使程序运行得更慢?

我正在尝试将此内容提交给SPOJ,它告诉我我的时间限制超出了......

#include <iostream>
#include <sstream>

using namespace std;

int main() {
    int testCases, first, second, counter = 0;
    bool isPrime = true;
    stringstream out;

    cin >> testCases;

    for (int i = 0; i < testCases; i++) {
        // get the next two numbers
        cin >> first >> second;

        if (first%2 == 0)
            first++;

        // find the prime numbers between the two given numbers
        for (int j = first; j <= second; j+=2) {
            // go through and check if j is prime
            for (int k = 2; k < j; k++) {
                if (j%k == 0) {
                    isPrime = false;
                    break;
                }
            }
            if (isPrime) {
                out << j << "\n";
            }
            isPrime = true;
        }
        out << "\n";
    }

    cout << out.str();

    return 0;
}

编辑:程序应该在输入中指定的数字之间生成素数。 (有关详细信息,请参见此处:Prime Generator Problem

-Tomek

6 个答案:

答案 0 :(得分:14)

这是天真算法之上的一步(跳过偶数)。我建议将Sieve Of Eratosthenes作为一种更有效的算法。从以上链接:

  

算法的复杂性是   O((nlogn)(loglogn))带有记忆   O(n)的要求。分段   Eratosthenes筛子的版本,   基本优化,如车轮   分解,使用O(n)运算   和O(n1 / 2loglogn / logn)位   存储器中。

你给出的算法在O(n ^ 2)附近。通过跳过evens得到的加速并不是那么好,因为在第一次测试时你会发现一个偶数不是素数。筛子具有更大的内存需求,但运行时复杂性远远优于大型 N

答案 1 :(得分:7)

您搜索很多的数字超过了您的数量 - 最多只需要转到<= (sqrt(num))

答案 2 :(得分:4)

这是一个简单的Eratosthenes筛子。它不需要预先声明一个大的布尔数组,但它在时间和空间上仍然是&gt;&gt; O(n)。但是,只要你有足够的记忆力,它应该明显快于你现在的天真方法。

#include <iostream>
#include <map>

using namespace std;

template<typename T = int, typename M = map<T, T> >
class prime_iterator {
    public:
        prime_iterator() : current(2), skips() { skips[4] = 2; }
        T operator*() { return current; }
        prime_iterator &operator++() {
            typename M::iterator i;
            while ((i = skips.find(++current)) != skips.end()) {
                T skip = i->second, next = current + skip;
                skips.erase(i);
                for (typename M::iterator j = skips.find(next);
                        j != skips.end(); j = skips.find(next += skip)) {}
                skips[next] = skip;
            }
            skips[current * current] = current;
            return *this;
        }
    private:
        T current;
        M skips;
};

int main() {
    prime_iterator<int> primes;
    for (; *primes < 1000; ++primes)
        cout << *primes << endl;
    return 0;
}

如果这对你来说仍然太慢,你可能想要追求Sieve of Atkin,一个优化的Eratosthenes筛选。

实际上,如果要生成的素数范围开始较低,这些只是相对有效。如果下限已经相当大并且上限不比下限大很多,那么筛分方法是浪费的工作,你最好不要运行primality test

答案 3 :(得分:3)

还有一件事,不要在循环中使用sqrt(n):

for(int k=1;k<sqrt(n);++k)

如果没有很好的优化,将在每次迭代中计算sqrt。

使用

for (int k=1;k*k < n;++k)

或者只是

int sq = sqrt ( n );
for (int k=1;k<sq;++k)

答案 4 :(得分:0)

可以稍微提高效率。你不需要在2开始k,你已经确定不测试偶数。所以从3开始k 然后每次将k递增2,因为您不需要测试其他偶数。 我能想到的最有效的方法是只测试一个数字是否可以被已知素数整除(然后当你找到另一个时,将其添加到你测试的列表中)。

答案 5 :(得分:0)

for (int k = 2; k < j; k++) {
     if (j%k == 0) {
         isPrime = false;
         break;
     }
}

应该是:

for(int k = 3; k <= j/2; k+=2 )
{
  if( j % k == 0 )
      break;
}

j / 2确实应该是sqrt(j),但它通常是一个足够好的估计。