素数筛的改进-线性筛o(n)时间复杂度

本文详细介绍了线性筛法(也称埃拉托斯特尼筛法)在寻找素数时如何实现O(n)的时间复杂度。通过最大因子和最小因子的概念,解释了如何避免重复标记,从而提高效率。线性筛法的基本思想是用每个素数的最大因子来标记合数,过程中注意避免M%P==0的情况,确保每个合数只被其最大素因子标记一次。文中还给出了C语言的代码示例,用于打印100以内的素数。
摘要由CSDN通过智能技术生成

素数筛的时间复杂度是o(nloglogn)无限趋近于o(n)
为什么线性筛时间复杂度是真真正正的o(n),因为完全避免了重复标记


一、基本思想概念

核心思想:用最大的因子来标记合数
有点迷糊?先上概念
约数和定理:对于一个大于1正整数n可以分解质因数
即任何大于1的整数都可以写成素因子连乘的形式(素因子:因子为素数)
在这里插入图片描述
举例:36 =2^2 * 3^2
最大因子M与最小因子P
N = M * P

以18分解为例
2 * 9     
3 * 6
6 * 3
9 * 2
9作为最大因子M,  2作为最小因子P,

二,表现形式

9作为最大因子M时:只能标记 1827 、36
因为18,才是36 的最大因子,所以36不能标记

三、标记过程

以2~20为例:
假设一个动态数组专门存放素数:array[] = {};
第一次标记:第一个未标记元素自动存入array[], array[] = {2}
即数组中元素作为最小因子P,2~20依次作为最大因子M
关键什么时候停止M* P
1:动态数组元素都作为最小P乘过了
2:M%P ==0(下面解释说)

过程一array[] = {2},最大因子M=2,最小因子P从array[0]开始遍历 ,即P=2M*P可标记———》4 自己列出数据划掉4
过程二3未标记 ,即array[] = {2、3} 最大因子M=3,最小因子P从array[0]开始遍历M*P可标记———》69
过程三4已经被标记 ,没有元素进入动态数组,array[] = {2、3} 最大因子M=4,最小因子P从array[0]开始遍历M*P可标记———》8、但不能标记12:P不能由2升到3,因为M%P= 0
当M%P= 0,说明会M中含有=P的因子 即4%2 = 2 ,若 P由2升到3,P就不是最小的因子了,因为4中含有真正的最小因子
过程四5未标记 ,即array[] = {2、3、5} 最大因子M=5,最小因子P从array[0]开始遍历M*P可标记———》1015 ,25本身就没有
过程五6已标记 ,即array[] = {2、3、5} 最大因子M=6,最小因子P从array[0]开始遍历M*P可标记———》12 ,同理因为M%P= 0 只能12
………………
过程nM=20 ,遍历完成, 标记结束输出array[]

是不是发现M%P=0 的奇妙之处了;下面我们来实现它

四、实现过程(打印100以内的素数)

代码如下:

#include <stdio.h>

#define max_n 100

int prime[max_n +5];
void init(){
    for(int i = 2; i <= max_n; i++){     //i相当于最大因子
        if(!prime[i]) prime[++prime[0]] = i;  //将prime[0]看做一个变量,用以记录动态数组中素数的个数
        for(int j = 1;j <= prime[0]; j++) {   //prime[j]相当于最小因子
            if(prime[j] * i > max_n) break;  //退出:相乘超过最大范围
            prime[prime[j] * i] = 1;
            if(i % prime[j] == 0) break;      //最大因子中含有=最小因子的因子,所以表  示最小因子
        }                                     //的动态数组素数不能向后遍历了
    }
}

int main(){
    init();
    for (int i = 1; i <= prime[0]; i++){
        printf("%d\t",prime[i]);
        if(i % 5 == 0) puts("\n");   //每5个数据换行输出 
    }
    puts("\n");
    printf("prime[0] = %d\n",prime[0 ]);
    return 0;
}

输出结果:
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值