求素数的程序是笔试或面试中会经常被问到的题目,大四找工作面试时,就被一个面试官问到了,虽然写出的代码能够完成题目要求,但是面试官并不满意,原因当然在程序的效率上,面试官反复问及如何对原有程序进行优化,想了半天除了将偶数剔除,再无其他想法,这也导致最后投递的岗位从研发变成offer中的测试。
素数的定义为,一个大于1的自然数,除了1和它本身外,不能被其他自然数整除(除0以外)的数称之为素数(质数);否则称为合数。对计算机专业的毕业生来说,这道题并不陌生,比如求N以内的所有素数,通常的解法为:
1 void PrimeNum(int n) 2 { 3 bool *bIsPrime = new bool[n+1]; //申请n+1来表示从1到n 4 for(int i=0; i!=n+1; i++) 5 if(i%2 == 0) 6 bIsPrime[i] = false; 7 else 8 bIsPrime[i] = true; 9 10 bIsPrime[2] = true; //2为素数 11 12 int j, k, nSqrt; 13 for(j=3; j<=n; j+=2) 14 { 15 nSqrt = sqrt(j); 16 for(k=3; k<=nSqrt; k++) 17 if(j%k == 0) 18 { 19 bIsPrime[j] = false; 20 break; 21 } 22 } 23 24 //cout<<n<<"以内的素数有:"<<endl; 25 //for(k=2; k<=n; k++) 26 // if(bIsPrime[k]) 27 // cout<<k<<" "; 28 //cout<<endl; 29 30 delete[] bIsPrime; 31 }
代码段line15-21,是这个求素数的核心思想:如果一个数是合数,那么它的最小质因数肯定小于等于他的平方根。例如:50,最小质因数是2,2<50的开根号。所以判断一个数是否是质数,只需判断它是否能被小于它开跟后的所有数整除。面试时给出的答案与上面思想一致,但是没有满足面试官对效率的要求。之后了解到筛选法求素数,核心思想是找到一个素数,那么这个素数与任何一个数的积是合数,这样就可以把这些合数筛掉。实现代码如下:
1 void PrimeNumFilter(int n) 2 { 3 bool *bIsPrime = new bool[n+1]; //申请n+1来表示从1到n 4 for(int i=0; i!=n+1; i++) 5 if(i%2 == 0) 6 bIsPrime[i] = false; 7 else 8 bIsPrime[i] = true; 9 10 bIsPrime[2] = true; //2为素数 11 12 int j, k; 13 int sqn = sqrt(n); //只需递增至sqrt(n)即可,因为对于一个数n来说,最大因子就是sqrt(n),这里指内层循环中j*k的值 14 for(j=3; j<=sqn; j+=2) 15 { 16 if(bIsPrime[j]) 17 { 18 for(k=2; j*k<=n; k++) 19 bIsPrime[j*k]=false; 20 } 21 } 22 23 //cout<<n<<"以内的素数有:"<<endl; 24 //for(k=2; k<=n; k++) 25 // if(bIsPrime[k]) 26 // cout<<k<<" "; 27 //cout<<endl; 28 29 delete[] bIsPrime; 30 }
代码段line15-19是实现筛选法的关键,如果一个数是素数,那么它与另一个数的乘积为合数。这个版本的是上一个版本的优化,关于效率的提高,来看看下面的测试代码,分别用两个版本的函数来计算10000000以内的所有素数,打印cpu耗时进行对比:
1 int _tmain(int argc, _TCHAR* argv[]) 2 { 3 clock_t start, end; 4 start = clock(); 5 PrimeNum(10000000); 6 end = clock(); 7 8 cout<<"cost cpu time: "<<end - start<<endl; 9 10 start = clock(); 11 PrimeNumFilter(10000000); 12 end = clock(); 13 cout<<"cost cpu time: "<<end - start<<endl; 14 15 return 0; 16 }
在VS2012中执行结果如下图:
可以看出使用筛选法求素数,程序的效率与普通版本相比得到了很大的提升,而这种优化非常考验程序员的观察力。写好一个程序,仍然需要仔细的分析代码,并且结合源数据的特点(有时会用到数学知识),看看有没有更好的算法,能够提高效率,优化性能。
来源:https://www.cnblogs.com/Tour/p/4056371.html