素数筛选算法,最经典的埃拉托斯特尼筛法,其基本思想是从2开始,依次将每个素数的倍数标记为合数,最终未被标记的数即为素数。它高效直观,时间复杂度约为O(n log log n),适合一次性筛选较大范围内的所有素数。


1. C/C++版代码:

// 位操作求素数(位筛法)
const int maxn = 1000000;
int prime[maxn], primenum;
int flag[maxn / 32 + 1];  // 每个int存储32个数的素性信息
// 生成素数并保存到prime数组
void wei_prime(int t) {
    primenum = 0;
    flag[0] |= 3;  // 标记0和1为非素数
    for (int k = 1; k <= t / 32 + 1; k++) flag[k] = 0;
    
    for (int i = 2; i <= t; i++) {
        if (!((flag[i / 32] >> (i % 32)) & 1)) {  // 检查第i位是否为0(素数)
            for (int j = i * i; j <= t; j += i)  // 从i*i开始标记
                flag[j / 32] |= (1 << (j % 32));  // 标记j为非素数
            prime[primenum++] = i;
        }
    }
}
// 仅生成标记数组,不保存素数
void wei_prime_onlyflag(int t) {
    flag[0] |= 3;
    for (int k = 1; k <= t / 32 + 1; k++) flag[k] = 0;
    
    for (int i = 2; i <= t; i++) {
        if (!((flag[i / 32] >> (i % 32)) & 1)) {
            for (int j = i * 2; j <= t; j += i)  // 从i*2开始标记
                flag[j / 32] |= (1 << (j % 32));
        }
    }
}
// 根据标记数组输出所有素数
void printby_flag(int t) {
    for (int i = 0; i <= t; i++) {
        if (!((flag[i / 32] >> (i % 32)) & 1))
            printf("%d ", i);
    }
}


2. Java版代码:

public class WeiPrime {
    static final int maxn = 1000000;
    static int[] prime = new int[maxn];
    static int primenum;
    static int[] flag = new int[maxn / 32 + 1];  // 每个int存储32个数的素性信息
    
    // 生成素数并保存到prime数组
    static void wei_prime(int t) {
        primenum = 0;
        flag[0] |= 3;  // 标记0和1为非素数
        for (int k = 1; k <= t / 32 + 1; k++) flag[k] = 0;
        
        for (int i = 2; i <= t; i++) {
            if (((flag[i / 32] >> (i % 32)) & 1) == 0) {  // 检查第i位是否为0
                for (int j = i * i; j <= t; j += i)  // 从i*i开始标记
                    flag[j / 32] |= (1 << (j % 32));  // 标记j为非素数
                prime[primenum++] = i;
            }
        }
    }
    
    // 仅生成标记数组,不保存素数
    static void wei_prime_onlyflag(int t) {
        flag[0] |= 3;
        for (int k = 1; k <= t / 32 + 1; k++) flag[k] = 0;
        
        for (int i = 2; i <= t; i++) {
            if (((flag[i / 32] >> (i % 32)) & 1) == 0) {
                for (int j = i * 2; j <= t; j += i)  // 从i*2开始标记
                    flag[j / 32] |= (1 << (j % 32));
            }
        }
    }
    
    // 根据标记数组输出所有素数
    static void printby_flag(int t) {
        for (int i = 0; i <= t; i++) {
            if (((flag[i / 32] >> (i % 32)) & 1) == 0)
                System.out.print(i + " ");
        }
    }
}


3. Python版代码:

maxn = 1000000
prime = [0] * maxn
primenum = 0
flag = [0] * (maxn // 32 + 1)  # 每个元素存储32个数的素性信息
# 生成素数并保存到prime数组
def wei_prime(t):
    global primenum
    primenum = 0
    flag[0] |= 3  # 标记0和1为非素数
    for k in range(1, t // 32 + 2):
        flag[k] = 0
    
    for i in range(2, t + 1):
        if ((flag[i // 32] >> (i % 32)) & 1) == 0:  # 检查第i位是否为0
            j = i * i
            while j <= t:  # 从i*i开始标记
                flag[j // 32] |= (1 << (j % 32))  # 标记j为非素数
                j += i
            prime[primenum] = i
            primenum += 1
# 仅生成标记数组,不保存素数
def wei_prime_onlyflag(t):
    flag[0] |= 3
    for k in range(1, t // 32 + 2):
        flag[k] = 0
    
    for i in range(2, t + 1):
        if ((flag[i // 32] >> (i % 32)) & 1) == 0:
            j = i * 2
            while j <= t:  # 从i*2开始标记
                flag[j // 32] |= (1 << (j % 32))
                j += i
# 根据标记数组输出所有素数
def printby_flag(t):
    for i in range(t + 1):
        if ((flag[i // 32] >> (i % 32)) & 1) == 0:
            print(i, end=' ')
点赞(0)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)