C语言埃氏筛法(素数筛选)

一、算法简介

埃拉托斯特尼筛法(埃氏筛) 是最经典、最高效的素数筛选算法之一,专门用于快速筛选出 2~n 范围内的所有素数。相比于普通暴力枚举判断素数的方法,埃氏筛通过倍数标记法剔除合数,极大降低了时间复杂度。

普通素数判断时间复杂度:O(n\\sqrt{n})

埃氏筛算法时间复杂度:O(n\\log\\log n)

该算法核心思想:素数的所有倍数一定是合数,只需遍历每个素数,将其所有倍数标记为合数,最终未被标记的数即为素数。

二、算法核心原理

  1. 数组初始化:定义布尔数组,默认将所有数字标记为素数;

  2. 特殊值剔除:0 和 1 不属于素数,手动标记为非素数;

  3. 遍历筛选:从 2 开始遍历,若当前数是素数,则将其所有平方及以上的倍数标记为合数(优化点:从 i\*i 开始遍历,避免重复筛选);

  4. 结果输出:遍历数组,所有标记为 true 的数值即为范围内的素数。

重点优化说明:常规筛法会从 2\*i 开始标记倍数,会产生重复筛选;从 i\*i 开始筛选,可大幅减少循环次数,提升运行效率。

cpp 复制代码
#include <stdio.h>
#include <stdbool.h>
#define MAXN 1000000

// 埃氏筛法筛选素数,全局数组默认初始化为false
bool is_prime[MAXN];

/**
 * @brief 埃氏筛核心函数,筛选2~n范围内的所有素数
 * @param n 筛选上限
 */
void eratosthenes_sieve(int n){
       数组:默认所有数为素数
       t i=0;i<=n;i++){
  is_prime[i]=true;
  
 // 0和1不是素数,单独标记
 is_prime[0]=is_prime[1]=false;
   // 遍历2~sqrt(n),筛选素数
  or(int i=2;i*i<=n;i++){
     如果当前数是素数,标记其所有倍数为合数
  if(is_prime[i]){
      从i*i开始标记,避免重复筛选
            for (int j = i * i; j <= n; j += i) {
                is_prime[j] = false;
            }
  }
   }

int main(){
     置素数筛选上限
     n=100;
 // 调用筛法函数
   atosthenes_sieve(n);
 
 // 格式化输出所有素数
  rintf("小于等于%d的素数有:\n", n);
        boo = true; // 控制逗号格式,避免末尾多余逗号
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) {
            if (!first) {
                printf(", ");
            }
            printf("%d", i);
            first = false;
        }
    }
       ("\n");
     turn 0;
}   
        re printfl first      p                   er           int   // 设     }
                                 //                         //       f     
                            }               for(in // 初始化

四、代码详细解析

1. 头文件与宏定义

  • #include <stdio.h>:提供输入输出打印功能;

  • #include <stdbool.h>:支持 C 语言布尔类型(true/false);

  • #define MAXN 1000000:定义数组最大容量,支持百万级数据筛选,可根据需求修改。

2. 全局标记数组

bool is_prime[MAXN] 作为素数标记数组:

  • true:代表当前下标数值为素数;

  • false:代表当前下标数值为合数/非素数。

3. 筛法核心函数

  1. 数组初始化:将 0~n 所有数值默认标记为素数;

  2. 特殊处理:0、1 不是素数,强制标记为 false;

  3. 外层循环:只遍历到 \\sqrt{n},减少循环次数(合数一定存在小于自身的因数);

  4. 内层循环:对每个素数 i,标记其所有大于等于i\*i 的倍数为合数。

4. 主函数格式化输出

通过 first 布尔变量控制输出格式,素数之间用逗号分隔,解决传统输出末尾多余逗号的问题,输出结果更整洁规范。

五、运行结果展示

代码默认筛选 100 以内所有素数,运行输出结果如下:

cpp 复制代码
小于等于100的素数有:
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97

六、算法优缺点分析

✅ 优点

  • 筛选效率极高,远优于暴力枚举法,适合大批量素数筛选;

  • 逻辑清晰、代码简洁,易于理解和二次修改;

  • 通过 i\*i 起始优化,规避了重复筛选问题。

❌ 缺点

  • 需要开辟大容量数组,占用内存空间,不适合超大范围素数筛选;

  • 仍存在少量重复标记(相较于线性筛),极致性能场景可使用欧拉线性筛优化。

七、拓展修改方式

  1. 修改筛选范围 :直接修改主函数中 int n=100; 的数值,即可筛选任意范围内的素数(不超过 MAXN 最大值);

  2. 扩大筛选上限 :修改宏定义 MAXN 的数值,可支持更大范围筛选;

  3. 统计素数个数:可新增计数器,遍历过程中统计范围内素数总数量。

八、总结

埃氏筛法是C语言算法入门的核心知识点,也是笔试、刷题的高频考点。相比于暴力判断,该算法通过空间换时间的思路,大幅提升了素数筛选效率。本文代码可直接复制编译运行,格式规范、注释详细,适合新手学习和项目直接使用。

相关推荐
曦樂~1 小时前
Cpp面筋
c语言·c++
Dream it possible!4 小时前
LeetCode 面试经典 150_多维动态规划_交错字符串(97_C++_中等)
算法·leetcode·面试·动态规划
心抵鹊4 小时前
算法之双指针系列(一)
算法·leetcode
十二5 小时前
【洛谷题解】P1083 [NOIP 2012 提高组] 借教室(二分答案 + 差分)
数据结构·c++·算法·蓝桥杯
小此方6 小时前
[算法实战论:动态规划]回文串问题的dp解法,回文串问题的母题,以及以此为基础的派生题
算法·动态规划
Pniubi6 小时前
力扣560.和为k的子数组
算法·leetcode·职场和发展
D e re k ZH7 小时前
C++ 从零入门(一):基础语法与程序结构
数据结构·c++·算法
Pniubi7 小时前
力扣438.找到字符串中所有字母异位词
算法·leetcode·职场和发展
東隅已逝,桑榆非晚10 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法
Eyfcom10 小时前
〖物联网终端实战 01〗UWB 室内高精度定位:仓储 AGV 与人员的厘米级轨迹追踪
物联网·算法·物流系统·快递系统·跨境物流快递系统·物联网终端实战