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