素數的定義:
指整數在一個大於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中判斷素數的方法是從程序的執行效率出發的,影響一個程序的執行效率有代碼的執行行數,以及代碼每行代碼消耗的時間長度,
因此減少循環次數以及將開根號計算代替為乘法運算等這些優化對執行效率都是有提高作用的。
附:以上的代碼參考了《編程珠玑》這本書,從書上學到了這些優化方法,提供給大家一起學習和分享。