質數篩法 nsqrt(n)/nloglog(n)/n
阿新 • • 發佈:2017-10-25
lap display 既然 技術 printf bre nlog play 隨筆
數論第一篇隨筆,就講一下質數篩法吧
質數,也稱做素數,在數學中有著重要的地位,有很多問題與算法都與質數有關(比如給你的hash函數選擇一個好的質數可以讓你的RP++)。對質數的最基本操作,就是輸出所有不大於n(n∈N*)的素數。
最簡單的方法:首先逐個枚舉從 2 ~ n 的數a,分別模 2 ~ sqrt(a)(即a的平方,想一下為什麽只需要判到sqrt(a)),若余數為0,那麽a不是質數。
實現代碼:
1 #include<stdio.h> 2 #include<math.h> 3 int n; 4 int main(){樸素算法5 scanf("%d",&n); 6 if(n<2){ 7 printf("0"); 8 return 0; 9 } 10 for(int i=2;i<=n;i++){ 11 bool f=true; 12 for(int j=2;j<=sqrt(i);j++) 13 if(i%j==0){ 14 f=false; 15 break; 16 }17 if(f) printf("%d ",i); 18 } 19 return 0; 20 }
以上樸素算法復雜度為O(nsqrt(n))
既然叫做樸素算法,那肯定有效率比它高的算法,那就是篩法求質數
它是通過劃掉n內每個已求出質數的所有倍數來實現,留下來的數就都是不大於n的質數
舉個例子,我們要求不大於15的所有質數: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1不是質數,2是最小的質數,從2開始劃掉2的倍數: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
輪到3,3沒有被劃掉,是質數,所以劃掉3的倍數: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
然後依次是5、7、11、13,重復上面的步驟。
其實這種情況下在劃掉所有3的倍數時就已經求出了所有不大於15的質數,即沒有被劃掉的數
實現代碼:
1 #include<stdio.h> 2 #include<string.h> 3 #define maxn 2333333 4 int n; 5 bool zs[maxn]; 6 int main(){ 7 memset(zs,0,sizeof(zs)); 8 scanf("%d",&n); 9 zs[0]=zs[1]=1; 10 for(int i=2;i*i<=n;i++)//i<=sqrt(n) ===> i*i<=n 11 if(!zs[i]) 12 for(int j=i+i;j<=n;j+=i) 13 zs[j]=1; 14 for(int i=2;i<=n;i++) 15 if(!zs[i]) 16 printf("%d ",i); 17 return 0; 18 }質數篩法
這種做法的算法復雜度為O(nloglog(n))
那有沒有比以上效率更高的做法呢,有的!
如果按以上方法做,會有計算冗余,比如60這個數,會被2,3,5各篩一次
所有就有了下面復雜度為O(n)的方法
實現代碼:
1 #include<stdio.h> 2 #include<string.h> 3 #define maxn 2333333 4 bool zs[maxn]; 5 int n,prime[maxn],num; 6 int main(){ 7 memset(zs,0,sizeof(zs)); 8 scanf("%d",&n); 9 zs[0]=zs[1]=1;num=0; 10 for(int i=2;i<=n;i++){ 11 if(!zs[i]){ 12 prime[++num]=i; 13 printf("%d ",prime[num]); 14 } 15 for(int j=1;j<=num&&i*prime[j]<=n;j++){ 16 zs[i*prime[j]]=1; 17 if(!(i%prime[j])) break; 18 } 19 } 20 return 0; 21 }質數的線性篩
這種方法就叫質數的線性篩法
詳細的以後再講吧
質數篩法 nsqrt(n)/nloglog(n)/n