素数的定义:
指整数在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。换句话说,只有两个正因数(1和自己)的自然数即为素数。
我将给出几种实现对自然数n进行素数的判断方法,主要从代码的执行效率上考虑这个问题。
首先,根据素数的定义,大家都会想到的一个方法就是遍历2~n-1,如果n能被其中的数整除,则n不是素数,否则为素数。
代码:
1 //方法1(遍历) 2 int prime_1(int n) 3 { 4 for(int i=2;i<n;i++) 5 { 6 if( n%i==0 ) 7 return 0; 8 } 9 return 1; 10 }
方法1最多的循环次数为:n-2,虽然能够解决问题,但这不是一个好方法。如果n值很大,可以采用另一种方法,就是对n开根号,只需遍历2~根号n。
代码:
1 //方法2(对n开根号) 2 int root(int n) 3 { 4 return (int)sqrt( (float)n ); 5 } 6 int prime_2(int n) 7 { 8 for(int i=2;i<=root(n);i++) 9 { 10 if( n%i==0 ) 11 return 0; 12 } 13 return 1; 14 }
细心的你可能会发现,在for循环中,虽然循环次数会减少,但是每次循环都要调用root(int n)函数,我们知道开根号计算在计算机中是非常耗费时间的,如果每次循环都要计算一次,程序的效率肯定不会高,由于n的开根号的值在程序运行过程中是不变的,可以用一个变量将这个值保存起来,每次循环不需要再去计算,只需取变量的值即可。
代码:
1 //方法3(只算一次开平方) 2 int prime_3(int n) 3 { 4 int bound=root(n); 5 for(int i=2;i<bound;i++) 6 { 7 if( n%i==0 ) 8 return 0; 9 } 10 return 1; 11 }
我们可以进一步进行考虑,素数肯定不会是偶数(因为所有的偶数都能被2整除,所以所有的偶数都不是素数),并且2、3、5都是素数,比2、3、5都要大的数如果能被2或者3或者5整除,那么这个数也不是素数。
根据这个思路,我们就有了第4种判断素数的方法。
代码:
1 //方法4(排除被2、3、5整除的数以及偶数) 2 int prime_4(int n) 3 { 4 if( n%2==0 ) 5 return (n==2); 6 if( n%3==0 ) 7 return (n==3); 8 if( n%5==0 ) 9 return (n==5); 10 11 int bound=root(n); 12 for(int i=7;i<=bound;i+=2) //偶数不是素数,不进行遍历 13 { 14 if( n%i==0 ) 15 return 0; 16 } 17 return 1; 18 }
现在我们的代码的执行效率比较高了,相对于第1种方法,循环执行的次数降低了不少,但是还有一个很影响程序执行效率的因素,那就是对n开根号的计算,开根号计算很耗费时间,因此我们需要消除开根号的计算。我们可以将开根号计算转换成乘法计算,乘法计算就要比开根号计算要快了,具体的实现过程请看以下的代码。
代码:
1 //方法5(乘法代替开方) 2 for(int i=7;i*i<=n;i+=2) 3 { 4 if( n%i==0 ) 5 return 0; 6 } 7 return 1;
总结:以上的5中判断素数的方法是从程序的执行效率出发的,影响一个程序的执行效率有代码的执行行数,以及代码每行代码消耗的时间长度,
因此减少循环次数以及将开根号计算代替为乘法运算等这些优化对执行效率都是有提高作用的。
附:以上的代码参考了《编程珠玑》这本书,从书上学到了这些优化方法,提供给大家一起学习和分享。