素数筛(算法篇)

算法之素数筛

素数筛

引言

  • 素数(质数)除了1和自己本身之外,没有任何因子的数叫做素数(质数)

朴素筛法(优化版)

概念

  • 朴素筛法:是直接暴力枚举2到当前判断的数x(不包括),然后看在这范围内是否存在因子,如果存在就不是素数,不存在就是素数,时间复杂度为O(n*n)
  • 优化版:优化版是用到了一个数学性质进行优化,使其只需要判断2到sqrt(x)的范围内,是否存在x的因子即可,时间复杂度为O(n*sqrt(n))

数学性质如果一个数x能够被一个大于1且小于等于sqrt(x)的整数整除,那么x必定能够被另一个大于1且大于sqrt(x)的整数整除

#include <iostream>
using namespace std;

//朴素筛素数判断算法时间复杂度:O(n)
bool isprime1(int x){
    if(x==1) return false;
    if(x==2) return true;
    for(int i=2;i<x;++i){
        if(x%i==0) return false;
    }
    return true;
}

//优化版素数判断算法时间复杂度:O(sqrt(n))
bool isprime(int x){
    if(x==1) return false;
    if(x==2) return true;
    for(int i=2;i<x/i;++i){
        if(x%i==0) return false;
    }
    return true;
}




int main() {
    //假设筛选出1-1000的素数
    for(int i=1;i<=1000;i+=2){
        if(isprime(i)) cout<<i<<endl;
    }
    system("pause");
    return 0;
}

欧拉筛(线性筛)

概念

  • 欧拉筛利用合数的数学性质,可以将素数筛的算法优化到时间复杂度为O(n)

合数除了1和自身之外还有其他正因子(除了 1 和自身以外的能够整除它的正整数),并且大于1的整数

数学性质:对于任意一个合数 x,它一定可以被其最小质因数(即最小的能整除 x 的质数)整除

算法具体操作

  1. 初始化一个标记数组vis[]和记录素数数组prime,vis所有元素初始化为false
  2. 2遍历到n(要筛选素数范围),如果vis[i]为false,则将i标记为素数,并将i记录在prime数组中,并将i的倍数j(j=i*i,i*i+i…)标记为合数(true)
  3. 遍历完所有的数后,prime数组中的数都为素数

总结:

在这个过程中,每个合数都会被标记为其最小质因数,这样能够确保每个合数只会被标记一次。由于每个合数只会被其最小质因数标记,因此在遍历过程中,每个合数只会被标记一次,而非多次,从而避免了重复标记,提高了效率。

const int N=1e8+10;
int prime[N];
bool vis[N];

//欧拉筛总体时间复杂度为O(n)
void isprimes(int n){
    int cnt=0;
    for(int i=2;i<=n;++i){
        if(!vis[i]) prime[cnt++]=i;
        for(int j=0;prime[j]<=n/i;++j){
            vis[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}

尾言

完整版笔记也就是数据结构与算法专栏完整版可到我的博客进行查看,或者在github库中自取(包含源代码)

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
素数筛法是一种用于查找素数的算法,其基本思路是从小到大依次枚举每一个数,如果该数还没有被标记为非素数,则将其所有的倍数都标记为非素数。最终没有被标记的数即为素数。 Python实现素数筛法通常有两种方式:埃氏筛和欧拉筛。 1. 埃氏筛法 埃氏筛法是一种最简单直观的素数筛法,其思想是从2开始,将每个质数的倍数都标记成合数,以达到筛选素数的目的。 具体实现过程如下: ``` def eratosthenes(n): is_prime = [True] * (n+1) # 先将所有数标记为素数 is_prime[0] = is_prime = False # 0和1不是素数 for i in range(2, int(n**0.5)+1): # 从2到根号n枚举每个质数 if is_prime[i]: # 如果i是素数 for j in range(i*i, n+1, i): # 将i的倍数都标记成合数 is_prime[j] = False return [i for i in range(2, n+1) if is_prime[i]] # 返回所有素数的列表 ``` 2. 欧拉筛法 欧拉筛法是一种时间复杂度更优秀的素数筛法,其核心思想是在筛选过程中避免重复标记合数,通过每个合数只被它的最小质因子筛选一次来实现。 具体实现过程如下: ``` def euler(n): is_prime = [True] * (n+1) # 先将所有数标记为素数 prime = [] # 存储所有素数 for i in range(2, n+1): # 从2到n枚举每个数 if is_prime[i]: # 如果i是素数 prime.append(i) # 加入素数列表 for p in prime: # 遍历已有的素数 if p * i > n: # 如果已有的最大素数乘以i已经超过n,就不必再筛了 break is_prime[p * i] = False # 将p*i标记成合数 if i % p == 0: # 如果i能够整除p,说明p是i的最小质因子 break return prime # 返回所有素数的列表 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值