素数

埃拉托斯特尼筛法

一、简介

   埃拉托斯特尼筛法,简称 埃氏筛或爱氏筛,是一种由埃及数学家埃拉托斯特尼所提出的一种简单检定素数的算法。

  我们详细列出算法如下:
  第一步,列出如下这样以2开头的序列:
  2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  第二步,标出序列中的第一个素数,主序列变成:
  2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  第三步,将剩下序列中,第二项开始每隔一项划掉(2的倍数,用红色标出。),主序列变成:
  2 3 5 7 9 11 13 15 17 19 21 23 25
  第四步,如果现在这个序列中最大数小于第一个素数的平方,那么剩下的序列中所有的数都是素数,否则返回第二步。
  本例中,因为25大于2的平方,我们返回第二步:
  剩下的序列中第一个素数是3,将主序列中3的倍数划出(红色),主序列变成:
  3 5 7 11 13 15 17 19 23 25
  我们得到的素数有:2,3。
  25仍然大于3的平方,所以我们还要返回第二步:
  现在序列中第一个素数是5,同样将序列中5的倍数划出,主序列成了:
  5 7 11 13 15 17 19 23 25
  我们得到的素数有:2 3 5 。
  因为25等于5的平方,跳出循环.
  结论:去掉红色的数字,2到25之间的素数是:2 3 5 7 11 13 17 19 23。
  筛选的主要方法
  1.划去2的倍数;
  2.划去3的倍数;
  3 划去5的倍数;(4的倍数同为2的倍数,已被划去)
  4.划去7的倍数;(6的倍数同为3的倍数,已被划去)
  5.划去11的倍数;(8和10的倍数同为2的倍数,而9的倍数也是3的倍数)
  所以验证一个数是否是素数,可以用它来除以2,3,5,7,11。
[cpp]  view plain copy
  1. //求2~2000 的所有素数.有足够的内存,要求尽量快  
  2. 方法一:  
[cpp]  view plain copy
  1. #include <iostream>  
  2. #include <cmath>  
  3. using namespace std;  
  4. int findvalue[2000]={2};  
  5. static int find=1;  
  6. bool adjust(int value){  
  7.     for (int i=0;i<find;i++)  
  8.     {  
  9.         if (value==2)  
  10.             return true;  
  11.         if (value%findvalue[i]==0)  
  12.             return false;  
  13.     }  
  14.     findvalue[find++]=value;  
  15.     return true;  
  16. }  
  17. void main(){  
  18.       
  19.     for(int i=2;i<100;i++)  
  20.         adjust(i);  
  21.     for (int i=0;i<find;i++)  
  22.         cout<<findvalue[i]<<endl;  
  23.     system("pause");  
  24. }  

 

 

方法二:

[cpp]  view plain copy
  1. void main(){  
  2.       
  3.     int a[20]={2};  
  4.     int k=3,i=1,j=1,m=0;  
  5.     for (;k<=20;k++)  
  6.     {  
  7.     for (m=0;m<j;m++)  
  8.     {  
  9.     if (k%a[m]==0)  
  10.     break;  
  11.     }  
  12.     if (j==m)  
  13.     a[j++]=k;  
  14.     }  
  15.     for (j=0;j<20;j++)  
  16.     {  
  17.     if (a[j]==0)  
  18.     break;  
  19.     cout<<a[j]<<endl;  
  20.     }  
  21.     system("pause");  
  22. }  


明白了!你说的“不是质数是素数”,应该是说: > 判断一个数是否是**素数(质数)**,而不是合数。 我们来重新梳理一下你的原始代码意图: 你希望判断一个数是否是**素数**(即质数),而你的函数 `haha` 实际上是判断一个数是否是**合数**(非质数),所以逻辑是反的。 --- ## ✅ 正确判断素数的函数(优化版) ```c #include <stdio.h> #include <stdbool.h> #include <math.h> // 判断一个数是否为素数 bool is_prime(int a) { if (a < 2) return false; // 0和1都不是素数 int sqrt_a = (int)sqrt(a); // 只需要检查到平方根即可 for (int i = 2; i <= sqrt_a; i++) { if (a % i == 0) return false; // 能整除则不是素数 } return true; } ``` > **说明**: - 时间复杂度从原来的 `O(a/2)` 优化到 `O(√a)`。 - 更加高效,尤其在处理大数时提升明显。 --- ## ✅ 修正主函数逻辑 你原来的主函数中,有一个 `while(k--)` 的写法是错误的,因为 `k` 是在循环中被递减的,导致第一次循环后 `k` 就变成 0,后续循环无法再进入。 我们来修正整个逻辑,使用**滑动窗口**或**前缀和**来高效地处理连续 `k` 个元素的和。 ### ✅ 改进后的完整代码 ```c #include <stdio.h> #include <stdbool.h> #include <math.h> bool is_prime(int a) { if (a < 2) return false; int sqrt_a = (int)sqrt(a); for (int i = 2; i <= sqrt_a; i++) { if (a % i == 0) return false; } return true; } int main() { int n, k; scanf("%d%d", &n, &k); int a[n]; // 输入数组 for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } int count = 0; // 对每个起点 i,计算连续 k 个元素的和(循环数组) for (int i = 0; i < n; i++) { int sum = 0; for (int j = 0; j < k; j++) { int index = (i + j) % n; // 循环取数 sum += a[index]; } if (is_prime(sum)) { count++; } } printf("%d\n", count); return 0; } ``` > **说明**: - `is_prime` 函数用于判断和是否是素数。 - 每次从位置 `i` 开始,取 `k` 个元素(循环数组),求和后判断是否为素数。 - 总时间复杂度为 `O(n * k + n * √sum)`,在合理范围内。 --- ## ✅ 示例 输入: ``` 5 2 2 3 5 7 11 ``` 输出: ``` 5 ``` 说明:所有连续两个数的和都是素数。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值