[算法]素数筛法

【方法一】

【代码一】

[cpp] view
plain
copy

  1. //判断是否是一个素数  
  2. int IsPrime(int a){  
  3.     //0,1,负数都是非素数  
  4.     if(a <= 1){  
  5.         return 0;  
  6.     }  
  7.     //计算枚举上界,为防止double值带来的精度损失,所以采用根号值取整后再加1,即宁愿多枚举一个,也不愿少枚举一个数  
  8.     int bound = (int)sqrt(a) + 1;  
  9.     for(int i = 2;i < bound;i++){  
  10.         //依次枚举这些数能否整除x,若能则必不是素数  
  11.         if(a % i == 0){  
  12.             return 0;  
  13.         }  
  14.     }  
  15.     return 1;  
  16. }  

【方法二】

【代码二】

[cpp] view
plain
copy

  1. #define MAXSIZE 10001  
  2.   
  3. int Mark[MAXSIZE];  
  4. int prime[MAXSIZE];  
  5.   
  6. //判断是否是一个素数  Mark 标记数组 index 素数个数  
  7. int Prime(){  
  8.     int index = 0;  
  9.     memset(Mark,0,sizeof(Mark));  
  10.     for(int i = 0;i < MAXSIZE;i++){  
  11.         //已被标记  
  12.         if(Mark[i] == 1){  
  13.             continue;  
  14.         }  
  15.         else{  
  16.             //否则得到一个素数  
  17.             prime[index++] = i;  
  18.             //标记该素数的倍数为非素数  
  19.             for(int j = i*i;j < MAXSIZE;j += i){  
  20.                 Mark[j] = 1;  
  21.             }  
  22.         }  
  23.     }  
  24.     return index;  
  25. }  

【方法三】

这种方法比较好理解,初始时,假设全部都是素数,当找到一个素数时,显然这个素数乘上另外一个数之后都是合数

把这些合数都筛掉,即算法名字的由来。但仔细分析能发现,这种方法会造成重复筛除合数,影响效率。

比如10,在i=2的时候,k=2*15筛了一次;在i=5,k=5*6 的时候又筛了一次。所以,也就有了快速线性筛法。

【代码三】

[cpp] view
plain
copy

  1. int Mark[MAXSIZE];  
  2. int prime[MAXSIZE];  
  3.   
  4. //判断是否是一个素数  Mark 标记数组 index 素数个数  
  5. int Prime(){  
  6.     int index = 0;  
  7.     memset(Mark,0,sizeof(Mark));  
  8.     for(int i = 2; i < MAXSIZE; i++)  
  9.     {  
  10.         //如果未标记则得到一个素数  
  11.         if(Mark[i] == 0){  
  12.             prime[index++] = i;  
  13.         }  
  14.         //标记目前得到的素数的i倍为非素数  
  15.         for(int j = 0; j < index && prime[j] * i < MAXSIZE; j++)  
  16.         {  
  17.             Mark[i * prime[j]] = 1;  
  18.             if(i % prime[j] == 0){  
  19.                 break;  
  20.             }  
  21.         }  
  22.     }  
  23.     return index;  
  24. }  

利用了每个合数必有一个最小素因子。每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。
代码中体现在:
if(i%prime[j]==0)break;
prime数组 中的素数是递增的,当 i 能整除 prime[j],那么 i*prime[j+1] 这个合数肯定被 prime[j] 乘以某个数筛掉。
因为i中含有prime[j], prime[j] 比 prime[j+1] 小。接下去的素数同理。所以不用筛下去了。

在满足i%prme[j]==0这个条件之前以及第一次满足改条件时,pr[j]必定是pr[j]*i的最小因子。

参考博文:点击打开链接

习题练习:点击打开链接

时间: 2024-08-30 03:46:52

[算法]素数筛法的相关文章

POJ3306 素数筛法

这题很明显得用素数筛法打出一个素数表 模拟一下求出第n个素数就可以了  水题啊.... #include <iostream> #include<cstdio> #include<cstring> using namespace std; #define max 1000005 bool isprime[max]; void getprime() { long long i,j; memset(isprime,1,sizeof(isprime)); isprime[1]

POJ 1595 素数筛法

题意让求一段素数中间的几个素数 用素数筛法筛出范围内的素数然后确定一下就行了 注意题目中1也算作素数了 具体看代码 #include <iostream> #include<cstdio> #include<cstring> using namespace std; #define max 2000 bool isprime[max]; int prime[max],nprime; void getprime() { memset(isprime,1,sizeof(is

POJ2262 素数筛法

素数筛法的水题 知道怎么筛就能做出来 在从3开始遍历那个表就行了 放假是不是不让做这种水题= =  #include <iostream> #include<cstdio> #include<cstring> using namespace std; #define max 1000010 bool isprime[max]; void getprime() { long long i,j; memset(isprime,1,sizeof(isprime)); ispr

素数判定算法的实现_C 语言

1. 素数判定问题 素数判定问题是一个非常常见的问题,本文介绍了常用的几种判定方法. 2. 原始算法 素数的定义是,除了能被1和它本身整除而不能被其他任何数整除的数.根据素数定义 只需要用2到n-1去除n,如果都除不尽,则n是素数,否则,只要其中有一个数能整除则n不是素数. 复制代码 代码如下: bool is_primer1(int num) {     int i;     for(i = 2; i < num; i++) {       if(num % i == 0) {        

《算法基础》——2.4 有关素数的运算

2.4 有关素数的运算 众所周知,一个素数是一个大于1的自然数(一个比0大的整数),它的因数只有1和它本身.一个合数是一个大于1并且非素数的自然数.素数在某些应用中起到重要的作用,在这些应用中素数的特质使得它们能够使特定程序变得简单或繁琐.例如,某些加密程序使用两个大素数的积来保证安全性.将一个由两个大素数相乘得到的数分解成两个大素数是十分困难的,而正是这个事实保证了算法的安全性.以下章节将讨论一些处理素数的常见算法.2.4.1 寻找素数因子寻找一个数的素因子最显而易见方法是尝试将这个数用比其小

C#算法设计与分析-寻找素数

素数寻找问题由来已久,一直是一些数学家追求的目的.关于素数的定义及性质,我就不在这里多叙了,相信大家都对此了如指掌.素数的寻找思路比较的简单,根据素数的性质(素数应该不能被除了1和它自身的其他数整除)我们可以从最小的素数2开始,一直到比它小1的数为止,用这些数去整除它,如果它能被整除则它必定不是素数,这是判断单个素数的方法(这个算法思想最简单,时间复杂度最大).对于寻找比某一个给定的整数值小的所有素数也可以采用这种方法,不过我们会发现,采用这种单个判断的方法所耗的时间比较多.比如查找不大于10的

筛法求2~1000之间的所有素数

筛法求素数首先要建立筛子,这里利用数组作筛子.下标对应于数,相应下标变量的值标志是否在筛子中:为1表示在筛子中,为.表示已被筛去,不在筛子中.然后找每一轮筛选种子,筛选种子是完成一轮筛选后的下一个最小的素数,初值为2. 对每一轮筛选种子,筛去其所有倍数,即相应下标变量的值赋值为O.倍数初值为筛选种子的2倍. 筛选完成,筛子中剩下的即为素数. 程序如下: /*程序8-14,筛法求2至1000之间的所有素数*/ main() { int a[1000];/*筛子数组*/ int i; int min

算法 c c++-求最大公约数和判断素数的最优算法

问题描述 求最大公约数和判断素数的最优算法 要求时间限制在1s之内的,测试数据最大到10的5次方,算法思想或者程序代码(C++或c) 解决方案 判断素数只需要把除数从2变到n的平方根就行了,最大公约数也就一样了

acm-区间筛法求区间内素数的个数

问题描述 区间筛法求区间内素数的个数 for(ll i = 2;i*i <=b;i++) is_prime_small[i] = true; for(ll i = 0;i <=b-a;i++) is_prime[i] = true; for(ll i = 2;i*i <=b;i++) { if(is_prime_small[i]) { for(ll j = 2*i;j*j <=b;j += i) is_prime_small[j] = false; for(ll j = max(2