本来都是没什么很难的技术的东西,但是时间长不写这样的,还是应该总结一下。
筛选法生成质数表(素数表)的基本思想如下:
假设有一个数组存放整数2 ~ N,如下所示:
2 3 4 5 6 7 8 9 10 11 12 13第一遍筛选去掉所有2的倍数,第二遍筛选去掉所有3的倍数,。。。第sqrt(N)遍筛选去掉所有sqrt(N)-1的倍数。
不考虑内存访问的时间问题,纯粹考虑时间复杂度,t(n)=n*( 1/2+1/3+1/4+.......+1/sqrt(n) ) ~=n*ln(n) (数学太菜了,计算不出来,google搜的,调和级数
代码如下:
#define Max_N 1300000 /* */
//#define Max_N 105 /* */
#define Max_P 100005 /* */
//please declare parameters here.
char rem[Max_N];
int prime[Max_P];
//please declare functions here.
int High;
void build_prime_table()
{
int i,j;
for(i=2;i*i<Max_N;i++)
{
for(j=i+i;j<Max_N;j+=i)
{
rem[j]=1;
}
}
for(i=2,j=0;i<Max_N;i++)
{
if(rem[i]==0)
{
prime[j++]=i;
}
}
High=j;
}
还可以用另一种筛选法:
将形如6n±1的数中的含有小于等于6n+1因子的数划去,剩下的数加上2和3,就是1到6*n+1中的所有的素数。
例如求100以内的素数,100以内形如6n±1的数由:5,7,11,13,17,19,23,25,29,31,35,37,41,43,47,49,63,55,59,61,65,67,71,73,77,79,83,85,89,91,95,97
小于100的素数有2,3,5,7那么在上面的数中由于没有偶数,可以划去5的倍数(5本身不划):25,35,55,65,85,95;划去7的倍数:49,77,91;那么剩下的数加上2和3就是100以内的素数,用同样的方法可以求得更大范围内的素数。
可以计算,这种方法的空间可以省一些,但是时间效率反倒不如第一种方法(主要原因是最后要去掉一些数,需要用到乘法)。
然后是二分查找,二分查找可以用库函数bsearch ,但是此处要查找包含数k的prime区间,即找到最大的比k小的素数,和最小的比k大的素数
因此需重写二分查找。
《编程珠矶》中说只有10%的程序员能写对二分查找。的确。
每次写二分查找的时候都十分小心。《编程珠矶》中说写二分查找(不光是二分查找,所有在区间内寻找元素的情况)应该总是维持一个前闭后开区间!
poj3518代码:
/*
* =====================================================================================
*
* Filename: 3518.c
*
* Description:
*
* Version: 1.0
* Created: 2012年06月08日 20时43分35秒
* Revision: none
* Compiler: gcc
*
* Author: MaZheng (blog.csdn.net/mazheng1989), emptystack@qq.com
* Company: Dalian University Of Technology
*
* =====================================================================================
*/
#include<stdio.h>
#define Max_N 1300000 /* */
//#define Max_N 105 /* */
#define Max_P 100005 /* */
//please declare parameters here.
char rem[Max_N];
int prime[Max_P];
//please declare functions here.
int High;
void build_prime_table()
{
int i,j;
for(i=2;i*i<Max_N;i++)
{
for(j=i+i;j<Max_N;j+=i)
{
rem[j]=1;
}
}
for(i=2,j=0;i<Max_N;i++)
{
if(rem[i]==0)
{
prime[j++]=i;
}
}
High=j;
}
int find_lower(int k)
{
int high=High,low=0,mid;
while(low<high)
{
mid=(high+low)>>1;
if(prime[mid]==k)
{
return -1;
}
else if(prime[mid]>k)
{
high=mid;
}
else
{
low=mid+1;
}
}
if(prime[low]<k)
{
return low;
}
return low-1;
}
int find_uper(int k)
{
int high=High,low=0,mid;
while(low<high)
{
mid=(high+low)>>1;
if(prime[mid]==k)
{
return -1;
}
else if(prime[mid]>k)
{
high=mid;
}
else
{
low=mid+1;
}
}
if(prime[low]<k)
{
return low+1;
}
return low;
}
int main()
{
if(freopen("input.txt","r",stdin)==NULL) perror("Can not open the input file!");
//input your ...
build_prime_table();
int k;
while(scanf("%d",&k)&&k)
{
int index_from,index_to;
if((index_from=find_lower(k))==-1||(index_to=find_uper(k))==-1)
{
puts("0");
}
else
{
// printf("%d %d\n",prime[index_to],prime[index_from]);
printf("%d\n",prime[index_to]-prime[index_from]);
}
}
return 0;
}