【问题标题】:Improvements for isPrime functionisPrime 函数的改进
【发布时间】:2012-03-13 11:40:58
【问题描述】:

互联网上有很多问题需要你找到素数,所以我决定写一组函数来找到它们。我使用 埃拉托色尼筛法 来生成素数,因为与其他算法相比,它实现起来既快速又容易。但是,我想知道我的代码而不是我的 method 是否效率低下。我使用的是 STL 容器/迭代器吗?我的代码中是否有任何部分减慢了程序的速度?

换句话说,它确实可以正确计算结果,但我想知道的是,它的效率是否可以通过一些算法改进来提高,而不仅仅是一些代码调整。

非常感谢任何帮助。

这是我的代码 (如果阅读困难,我深表歉意)

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

#define initial_prime_barrier 100
bool isFlagged(int i) { return i == 0; }
bool isNextStart(int i) { return i != 0; }

vector<int> generatePrimesBelow(int limit)
{
   vector<int> primes;
   for (int i = 2; i < limit; i++)
   {
      primes.push_back(i);
   }  
   vector<int>::iterator currentStart = primes.begin();
   do
   {
      int numberAtStart = *currentStart;
      vector<int>::iterator currentNumber = currentStart + numberAtStart;
      do
      {
         *currentNumber = 0;
         advance(currentNumber, numberAtStart);
      } while (currentNumber < primes.end());
      currentStart = find_if(currentStart + 1, primes.end(), isNextStart);
   } while ((*currentStart) * (*currentStart) < limit);
   vector<int>::iterator newEnd = remove_if(primes.begin(), primes.end(), isFlagged);
   primes.erase(newEnd, primes.end());
   return primes;
}

bool isPrime(int number)
{
   static vector<int> primes = generatePrimesBelow(initial_prime_barrier);
   static int numPrimes = primes.size();
   static int largestPrime = primes[numPrimes-1];
   static int halfwayPrime = primes[numPrimes/2];
   if (number == largestPrime)
   {
      return true;
   }
   else if (number < largestPrime)
   {
      if (number == halfwayPrime)
      {
         return true;
      }
      else if (number > halfwayPrime)
      {
         for (int i = numPrimes/2; i < numPrimes; i++)
         {
            if (number == primes[i])
            {
               return true;
            }
         }
      }
      else if (number < halfwayPrime)
      {
         for (int i = numPrimes/2; i >= 0; i--)
         {
            if (number == primes[i])
            {
               return true;
            }
         }
      }
   }
   else if (number > largestPrime)
   {
      primes = generatePrimesBelow(number + number);
      numPrimes = primes.size();
      largestPrime = primes[numPrimes-1];
      halfwayPrime = primes[numPrimes/2];
      return isPrime(number);
   }
   return false;
}

int main (int argc, char * const argv[]) 
{
   const int number = 123123;
   cout << (isPrime(number) ? "YES" : "NO") << endl;
}

【问题讨论】:

标签: c++ algorithm performance optimization primes


【解决方案1】:

是的,这是你的方法。几件事。您不需要数组来保存数字,数组中每个条目的地址就是数字本身。您只需要它们保存两个值 - truefalse。所以让你的数组vector&lt;bool&gt;,它会更紧凑。然后,在您的内部循环中,您从x+x 开始,并按x 的步骤前进。您应该从x*x 开始,并按2*x 的步骤前进——这将适用于除2 之外的所有x。使其成为特例,或在初始化循环中标记这些偶数。或者将i 的条目视为代表数字2*i+1 并完全不处理事件。这应该会加快您的筛选代码。最后,您不需要特殊的 find_if 调用及其所有机制,您只需检查循环中出现的当前条目即可。

(编辑:)在您的isPrime 中,您手动执行二进制搜索,但STL 中已经存在binary_search 算法。如果您保持 vector&lt;bool&gt; 筛子数组原样而不进行压缩,您将根本不需要它。那么isPrime(i) 只需检查索引i 处的数组值是否仍然是true

(edit2:) 现在,关于效率。你重新计算到n+n,可能是为了测试更多的数字。如果你只测试几个,简单的赔率试除会更快。如果要测试的数字都在一个狭窄的上部区域,那么您最好的选择是偏移筛,将下筛完成直到测试区域上限的sqrt时间>。如果数字分布广泛,则可以使用您当前的整个数组方法。

这里要使用的关键事实是,在值 m 以下大约有 n ~= m/log m 质数,从 0m 筛选数组需要 O(m*log (log m)) 时间,而筛选上ab 之间的区域,即宽度为d=b-a,由r=sqrt b 以下的所有素数组成,所需时间与d*log (log r) 成正比。

另外,当你增加你的筛子阵列时,最好扩大,而不是重新计算整个。素数都在那里。为了筛选附属物,有必要遍历筛选阵列中的所有素数,直到其新上边缘的sqrt。这让人想起 分段筛,尽管每个新的分段都代替了之前的分段,或者在任何情况下都与之前的分段分开。

【讨论】:

  • 感谢您的提示!但是我有一个问题,我应该用什么替换find_if()?我需要它来找到筛子的下一个起点,基本上是第一个未被过滤的值,即true。至于isPrime() 函数的效率,您是说我将过滤结果保留为vector&lt;bool&gt; 并将其偏移sqrt(n)
  • @rcplusplus 筛子数组保存布尔值;所以for(;i&lt;m;++i) if(s[i]) { "set i*i, i*i+2*i, ..., m to False" }; } 就是你所需要的。无论如何,您都可以遍历它们,只需跳过那些已经是 false 的(即,代表复合材料)。 index 是数字。至于“偏移”,不,你从0到上限的sqrt。但是您也可以在上面设置另一个阵列来标记它,就像您筛选主筛阵列一样。最后,你会让第二个数组也保存素数。您必须在标记时为每个素数计算偏移量in it
猜你喜欢
  • 1970-01-01
  • 2020-04-07
  • 1970-01-01
  • 2011-02-26
  • 1970-01-01
  • 1970-01-01
  • 2017-01-24
  • 1970-01-01
  • 2022-11-23
相关资源
最近更新 更多