前几天同学让我帮他做道题,关于求素数的,十亿两分钟内出结果 。 (编译器 mingw-g++)
最开始是用的最常见的欧几里得筛选法
{
int s = ( int )sqrt(x);
for ( int i = 3 ;i <= s;i += 2 )
{
if (x % i == 0 )
return false ;
}
return true ;
}
也就是一个双重循环,外层把数从1到n 跑一遍,只测试奇数。时间复杂度大约是O(N3/2).后来发现速度是相当的慢,这种算法效率无法达到要求。
改用BigMap算法。这里我先把1到10万内的素数求出来,放在一个数组里面(方法还是用的上面那种,这里对效率影响不是很大。总共用时在1秒以内)。然后以此为基数再判定后面的数。
{
for ( int i = 1 ;x[i] * x[i] <= a;i ++ )
{
if (a % x[i] == 0 )
return false ;
}
return true ;
}
这里x[ ]里面是1到10万的素数,x[0]=2可以不用测。时间复杂度约为O(10000N).
这个时候求1千万内的素数大概用时6.22秒,2千万 15.22秒,3千万 25.95秒。
后来测十亿时,半个小时没出结果,我把素数输出到一个文件里面,大小约320M。我看了下,这时才走到6亿9千万。
最后,考虑到函数入栈出栈的时间,我把BigMap内联了,这里是全部的代码。
#include < fstream >
#include < math.h >
#include < time.h >
using namespace std;
bool IsPrime( long x);
void MakeBasePrime( long * );
const int BASE = 9592 ;
// 9592 is the number of the primes in 1 to 100000
int main()
{
clock_t start,finish;
long range;
long count = 0 ;
long baseprime[BASE];
cout << " Input the max number: " ;
cin >> range;
start = clock();
MakeBasePrime(baseprime);
ofstream out ( " prime.txt " );
for ( int i = 100001 ;i <= range;i += 2 )
{
if (i % 3 == 0 || i % 5 == 0 || i % 7 == 0 || i % 11 == 0 || i % 13 == 0 || i % 17 == 0 || i % 19 == 0 )
continue ;
bool flag = true ;
for ( int j = 8 ;baseprime[j] * baseprime[j] <= i;j ++ )
{
if (i % baseprime[j] == 0 )
{
flag = false ;
break ;
}
}
if (flag)
{
out << i << " " ;
count ++ ;
if (count % 10 == 0 )
out << endl;
}
}
cout << " The least prime count = " << count;
finish = clock();
cout << " The whole time lapse is " << ( double )(finish - start) / CLOCKS_PER_SEC;
cin. get ();
return 0 ;
}
bool IsPrime( long x)
{
int s = ( int )sqrt(x);
for ( int i = 3 ;i <= s;i += 2 )
{
if (x % i == 0 )
return false ;
}
return true ;
}
void MakeBasePrime( long x[])
{
int k = 1 ;
x[ 0 ] = 2 ;
ofstream out ( " baseprime.txt " );
out << x[ 0 ] << " " ;
for ( int i = 3 ;i < 100000 ;i += 2 )
{
if (IsPrime(i))
{
x[k] = i;
out << x[k] << " " ;
k ++ ;
if (k % 10 == 0 )
out << endl;
}
}
cout << " The count of prime range 1 to 100000 = " << k << endl;
}
在用BigMap判定素数前,先用if语句测试前几个。因为在多次实验中这样时间有一定的减少,但如果if语句再多测几个数,速度会变慢,具体原因还不清楚,可能是编译器优化的原因。
这里是几组测出来的时间:
1千万 5.828 s
2千万 14.313 s
3千万 24.109 s
1亿 125.094 s
如果不输出到文件,时间每1千万大概能减少1秒。这里看来十亿估计也在半小时左右。
如果有高人能有更好的解法,欢迎赐教。