判断素数(从暴力筛选,到线性筛选和优化)

【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结束。(左图为素数表,右图为程序运行结构)

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章