如何更快地制作以下C ++程序?

时间:2015-03-31 12:11:22

标签: c++ performance

问题的链接 - https://www.hackerrank.com/contests/freshers-challenge-2/challenges/counting-the-steps

问题如下 - 找出a和b之间的素数(包括a和b,以防它们是素数。)

我使用了Eratosthenes的筛子来解决问题,但我在两个测试用例上超时。

特别是对于一个有10,000个数字的测试用例,我的C ++程序在CodeBLocks中花了大约10秒钟。我正在下面插入代码片段 -

for(int i=2;i<=upperbound;i++)
{
    prime[i-2]=i;
}
int sq=sqrt(upperbound);
for(int i=0;prime[i]<=sq;i++)
{
    if(prime[i]!=0)
    {
        int j=i+prime[i];
        for(;j<m;j+=prime[i])
        {
            prime[j]=0;
        }
    }
}

这是筛子的代码片段。我的输出都是正确的,但我怎样才能使这个程序更快。

编辑:在用sq

替换upperbound之后解决了分段错误

3 个答案:

答案 0 :(得分:2)

您正在使用sqrt,这可能非常耗时,尤其是在找到双根时。之后你甚至都不使用sq

修改:尝试在循环中将upperbound替换为sq。它会解决一些速度问题,但不会解决因分配太大内存而导致的段错误。


筛选算法的问题在于它为所有数字分配完整数组。

查找素数的另一种方法是通过将它们除以素数来检查所有数字,直到它们的平方根。对该算法的简单优化是避免偶数。并将仅存储结构中的素数。

int lastBound = 0; //avoids doing too many multiplications
vector<int> primes;

primes.push_back(2);

for (int i = 3; i <= upperbound; i+= 2) {
    bool prime = true;
    for(int j : primes) {
         if (j > lastBound && j * j > i) {
             lastBound = j;
             break;
         }

         if (i%j == 0) {
             prime = false;
             break;
         }
    }

    if (prime) {
        primes.push_back(i);
    }
}

然后你在列表中有素数,你可以将它转换成你拥有的数组,集合或其他任何数据。

有些动态分配可能会导致一些延迟,但对于大小为vector的{​​{1}},只有O(log(n))分配。可能会有进一步的优化,但为了你的目的,它应该足够了。

答案 1 :(得分:0)

我在代码中看到的吞咽者唯一一次使用sqrt

您可以使用digit by digit method in base 2

但这是一个小改进。

您必须更改算法才能获得更好的效果。 搜索素数是一个难题,并且有很多最差解决方案(例如,您可以使用pseudo-prime filters ...)

答案 2 :(得分:0)

您有效地在数组中存储两次素数。 prime[i] == i+2,因此您可以将int j=i+prime[i];替换为int j=i+(i+2);

现在,如果您不再需要实际值,则只能存储一个位:std::vector<bool> prime(upperbound, true);。这减少了95%(可能)所需的内存,这使得你的筛子很可能适合CPU缓存。

prime的开头保存2位是一个坏主意。其他地方的单个i-2指令将至少占用整个字节,并且还会花费您实际的运行时间。