判斷一個數是否為質數/素數——從普通判斷演算法到高效判斷演算法思路
阿新 • • 發佈:2019-01-07
最直觀的方法,根據定義,因為質數除了1和本身之外沒有其他約數,所以判斷n是否為質數,根據定義直接判斷從2到n-1是否存在n的約數即可。C++程式碼如下:
bool isPrime_1( int num )
{
int tmp =num- 1;
for(int i= 2;i <=tmp; i++)
if(num %i== 0)
return 0 ;
return 1 ;
}
2)直觀判斷法改進
上述判斷方法,明視訊記憶體在效率極低的問題。對於每個數n,其實並不需要從2判斷到n-1,我們知道,一個數若可以進行因數分解,那麼分解時得到的兩個數一定是一個小於等於sqrt(n),一個大於等於sqrt(n),據此,上述程式碼中並不需要遍歷到n-1,遍歷到sqrt(n)即可,因為若sqrt(n)左側找不到約數,那麼右側也一定找不到約數。C++程式碼如下:bool isPrime_2( int num ) { int tmp =sqrt( num); for(int i= 2;i <=tmp; i++) if(num %i== 0) return 0 ; return 1 ; }
3)另一種方法
方法(2)應該是最常見的判斷演算法了,時間複雜度O(sqrt(n)),速度上比方法(1)的O(n)快得多。最近在網上偶然看到另一種更高效的方法,暫且稱為方法(3)吧,由於找不到原始的出處,這裡就不貼出連結了,如果有原創者看到,煩請聯絡我,必定補上版權引用。下面講一下這種更快速的判斷方法;
首先看一個關於質數分佈的規律:大於等於5的質數一定和6的倍數相鄰。例如5和7,11和13,17和19等等;
演算法效能測試:編寫測試程式碼,使用較多資料測試比較幾種方法的判斷效率,資料量40w,程式碼如下:bool isPrime_3( int num ) { //兩個較小數另外處理 if(num ==2|| num==3 ) return 1 ; //不在6的倍數兩側的一定不是質數 if(num %6!= 1&&num %6!= 5) return 0 ; int tmp =sqrt( num); //在6的倍數兩側的也可能不是質數 for(int i= 5;i <=tmp; i+=6 ) if(num %i== 0||num %(i+ 2)==0 ) return 0 ; //排除所有,剩餘的是質數 return 1 ; }
#include <iostream>
#include <string>
#include <ctime>
#include <vector>
using namespace std;
bool isPrime_1( int num );
bool isPrime_2( int num );
bool isPrime_3( int num );
int main()
{
int test_num =400000;
int tstart ,tstop; //分別記錄起始和結束時間
//測試第一個判斷質數函式
tstart=clock ();
for(int i= 1;i <=test_num; i++)
isPrime_1(i );
tstop=clock ();
cout<<"方法(1)時間(ms):" <<tstop- tstart<<endl ;//ms為單位
//測試第二個判斷質數函式
tstart=clock ();
for(int i= 1;i <=test_num; i++)
isPrime_2(i );
tstop=clock ();
cout<<"方法(2)時間(ms):" <<tstop- tstart<<endl ;
//測試第三個判斷質數函式
tstart=clock ();
for(int i= 1;i <=test_num; i++)
isPrime_3(i );
tstop=clock ();
cout<<"方法(3)時間(ms):" <<tstop- tstart<<endl ;
cout<<endl ;
system("pause" );
return 0 ;
}
執行結果如下;
可以看出,判斷到40w,效率上方法(1)明顯要差得多,方法(2)和方法(3)在這種測試數量下時間相差2倍多單獨對比方法(2)和(3),資料量加到1000w,結果如下:
可以看出,方法(2)和方法(3)在這種測試數量下時間相差依然是2倍多,不過已經是很不錯的提升。對了,附上執行環境,CPU-i5-3210,記憶體4G,win7,vs2012。好了,判斷質數的方法暫時就到這裡,不足之處歡迎各道友指出。