素数问题(转)
素数问题(转)
参考文:http://blog.csdn.net/hechenghai/article/details/6733907
定义:除了1和其本身,没有其他约数的数。
算法:用n分别试除2到sqrt(n)的数,如果中间有一个能整除,即为合数,否则即为素数。
著名的素数筛选法:
公元前300多年,学者埃拉托色尼提出了一种方法,他在一张纸上写上自然数列的数字,把它贴在一个柜子上,然后把其中的合数一个一个地挖去。得到一个有许多小孔的像筛子一样的东西,所有的合数都好像被筛子筛去了一样。埃拉托色尼是怎样筛法呢?他若造一张1到50的素数表,首先写上1到50的所有自然数,然后先划去1,把2留下,再划去其他所有2的倍数,把3留下。再划去其他所有3的倍数,把5留下。又划去其他所有5的倍数……以此类推,可以得到50以内的所有素数。
按照埃拉托色尼的筛法,会不会划到最后都是合数呢?也就是素数的个数是不是有限的呢? 约公元前275年,希腊著名的数学家欧几里德用巧妙的方法证明了素数是无限的。
C语言算法
//求1000以内所有素数,用筛选法
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define SIZE 1000
int main(int argc, char *argv[])
{
int sign[SIZE];
int i, j;
for (i = 0; i < SIZE; i++){
sign[i] = 1;
}
for (i = 2; i <= sqrt((double)SIZE); i++){
if (sign[i]){
for (j = 2; j <= SIZE / i; j++){
sign[i*j]=0;
}
}
}
for (i = 2; i < SIZE; i++){
if(sign[i])
printf("%d,",i);
}
system("PAUSE");
return 0;
}
素数判定方法:
1.遍历2以上N的平方根以下的每一个整数,是不是能整除N;(这是最基本的方法)
C语言描述:
int isPrimeNumber(int n){
int i;
for (i = 2; i <= sqrt(n); i++){
if (n % i == 0) return 0;
}
return 1;
}
2.遍历2以上N的平方根以下的每一个素数,是不是能整除N;(这个方法是上面方法的改进,但要求N平方根以下的素数已全部知道)
但以上算法都不适合长整数的素数判断,通常会采用概率算法。(这里就不贴概率算法了。)
bool is_prime(int n)//判断n是否为素数,是素数返回1
{
int i;
bool flag = 1;
for(i = 2; i <= sqrt(n); i++)
{
if(n % i == 0){
flag = 0;
break;
}
}
return flag;
}
小范围内筛素数(数据不太大):
#define Max 1000
int Prime[500];
int q;
void get_prime()
{
q = -1;
Prime[++q] = 2;
Prime[1] = 3;
int i;
for(i = 5; i <= Max; i++){
for(j = 0;Prime[j]*Prime[j] <= i &&i%Prime[j] != 0; j++);
if(Prime[j]*Prime[j] > i)Prime[++q] = i;
}
}
大范围内筛素数的普通筛法(很慢):
#define Max 1000000
int Prime[500000];
bool IsPrime[Max] = {1};
int q;
void get_prime()
{
q = -1;
int i,j;
for(i = 2; i*i < Max; i++){
if(IsPrime[i] == 1){
for(j = i+i; j < Max; j += i){
IsPrime[j] = 0;
}
}
}
for(i = 2; i < Max; i++){
if(IsPrime[i] == 1)
Prime[++q] = i;
}
}
大范围内素数的线性筛法(比普通筛法更快)
#define Max 1000000
int Prime[500000];
bool IsPrime[Max] ;
int q;
void get_prime()
{
memset(IsPrime,true,sizeof(IsPrime));//将数组初始化为true
q = -1;
int i,j;
for(i = 2; i < Max; i++){
if(IsPrime[i] == 1)
Prime[++q] = i;
for(j = 0;j <= q && Prime[j] * i < Max; j++){
IsPrime[Prime[j] * i] = 0;
if(i % Prime[j] == 0)break;
}
}
}
求某一区间(a,b)内的素数
有时候我们碰到的问题是要求求出a b间的素数,而a又比较大,这种情况下就可以用这种方法实现(a>2)
注意:要先通过以上几种方法求出2到sqrt(a的最大取值)范围内的素数存入Prime[].
int prime[500000];
bool isprime[1000000];
int qt;
void get_prime1(int a,int b)
{
int i,j,k;
for(i = 0; i <= b - a; i++)
isprime[i] = 1;
for(i = 0; Prime[i]*Prime[i] <= b && i <= q;i++){
k = a/Prime[i];
if (k*Prime[i] < a) k++;
if (k <= 1) k++;
while(k*Prime[i] <= b){
isprime[k*Prime[i] - a] = 0;
k++;
}
}
qt = -1;
for(i = 0; i <= b - a; i++)
{
if(isprime[i] == 1)
prime[++qt] = i + a;
}
}