【Prime Number】
素數定義:素數就是質數,指出了“1”和他本身,沒有其他因數的數字,
0,1不是素數,第一個素數是2,依次是2,3,5,7,11……
以搜索1000以內的素數爲例,判斷出來的素數存放於一維數組中。
1、一般遍歷(雙重循環)
採用雙重循環,表層循環遊標 J 負責遍歷2-1000,內層遊標K的範圍是[2,根號J],在內層遊標遍歷的過程中,如果
表層循環遊標J如果能整除K,則說明J代表的數字不是素數,當K遍歷完[2,根號J],仍沒找到因數,說明J是個素數。存入數組。
#include <math.h>
#include <stdio.h>
#define Max 1000 //Max = 1e3 =1 * 10的3次方,即一千
int sushu[Max]={0},count=1; //保存素數在數組中,count計數素數個數
void prime();
int main(){
prime();
int i;
for(i=1; i<Max; i++){
if(sushu[i] == 0){
break;
}
printf("%3d ",sushu[i]);
if(i%10 == 0){
printf("\n");
}
}
return 0;
}
void prime(){
int total; //每次循環等於 sqrt(j),取[ 2,sqrt(j) )區間判斷素數
int j,k;
for(j=2; j<Max; j++){
total=sqrt(j);
for(k=2; k<=total; k++){
if(j%k == 0){
break;
}
}
if(k > total){
sushu[count++]=j;
}
}
}
2、埃氏篩選(未優化的線性篩選)
我們知道合數(非素數)是可以用素數的倍數表示,有的更可以用兩個合數表示,所以篩選出素數同時,篩掉素數的倍數。篩掉的合數,也可以用來篩掉合數的倍數。
例如,2是素數,則篩掉4,6等,篩掉了在IsPrime數組置零,表示非素數,下一步3是素數,篩掉6,9等,因爲在2處,4被篩掉了,執行篩選會篩掉8,篩選5,
5是素數,就有篩掉10,15之類,依次類推,6篩掉了,篩掉12等,下一個7……
這樣我們篩選出非素數的速度高於篩出素數,保證篩出的都是素數(1000以內素數168個,遠遠少於合數)
篩選的方法,sushu[]數組負責存儲素數,IsPrime[]數組每一位數組元素,代表數組下標數字是不是素數,0代表不是,1代表是。負責協助存儲素數。
剛開始假設2-1000全部都是素數,所以IsPrime[]剛開始全部初始化爲0。我們知道這個第一個素數是2,所以就有
for(j=2; j<Max; j++){
if(IsPrime[j]){ //IsPrime[j]=1,說明是素數
sushu[count++]=j;
}
for(k=j*2; k<=Max; k+=j){
IsPrime[k]=0;
}
}
J的for循環,提供便利2-1000,if根據IsPrime數組判斷是否爲素數,內層的遊標爲K的for循環,負責篩出素數後繼續篩出他的倍數,如果當前遍歷到的是非素數,
則篩非素數的倍數,這樣就把大量的非素數篩除出去了。
#include <stdio.h>
#define Max 1000
int sushu[Max]={0},count=1; //sushu數組用來保存1000以內素數,count作爲下標
int IsPrime[Max];
//int IsPrime[Max]={1}; //IsPrime數組0代表不是素數,1代表是素數
//用來協助篩選素數,剛開始認爲所有數字都是素數
void prime();
int main(){
prime();
int i=1;
for(; i<Max; i++){
if(sushu[i] == 0){
break;
}
printf("%3d ",sushu[i]);
if(i%10 == 0){
printf("\n");
}
}
return 0;
}
void prime(){
memset(IsPrime,1,sizeof(IsPrime));
IsPrime[0]=IsPrime[1] =0; //0,1不是素數,第一個素數是2
int j,k;
for(j=2; j<Max; j++){
if(IsPrime[j]){ //IsPrime[j]=1,說明是素數
sushu[count++]=j;
}
for(k=j*2; k<=Max; k+=j){
IsPrime[k]=0;
}
}
}
3、優化後的線性篩選(歐拉篩選)
主要是優化了像是素數2,3都會篩除6這樣的重複。
#include <stdio.h>
#define Max 1000
int sushu[Max]={0},count=1; //sushu數組用來保存1000以內素數,count作爲下標
int IsPrime[Max];
//int IsPrime[Max]={1}; //IsPrime數組0代表不是素數,1代表是素數
//用來協助篩選素數,剛開始認爲所有數字都是素數
void prime();
int main(){
prime();
int i=1;
for(; i<Max; i++){
if(sushu[i] == 0){
break;
}
printf("%3d ",sushu[i]);
if(i%10 == 0){
printf("\n");
}
}
return 0;
}
void prime(){
memset(IsPrime,1,sizeof(IsPrime));
IsPrime[0]=IsPrime[1] =0; //與上同理
int j,k;
for(j=2; j<Max; j++){
if(IsPrime[j]){
sushu[count++]=j;
}
for(k=1; k<count && sushu[k]*j<Max; k++){
IsPrime[sushu[k]*j]=0;
}
}
}
4、區間篩選
假設篩選[a,b)區間,所以先篩出[2,根號b)的素數,然後篩出[2,根號a)的素數,兩者減去重疊就好了。不多說了
5、源碼+思考+理解
數據結構部分會繼續更新,即使環境惡劣
附圖:1000以內的素數表,共168個素數,2開始,997結束。(左圖爲素數表,右圖爲程序運行結構)