Eratosthenes筛选法与欧拉筛选法

素数筛选(只做最快的男人)

一、Eratosthenes筛选

  1. 原理:
    把质数(最初只知道2是质数)的倍数都去掉。

  2. 步骤:
    (1)先把1删除(1既不是质数也不是合数)

(2)读取队列中当前最小的数2,然后把2的倍数删去

(3)读取队列中当前最小的数3,然后把3的倍数删去

(4)读取队列中当前最小的数5,然后把5的倍数删去

......

(n)读取队列中当前最小的状态为true的数n,然后把n的倍数删去

3.代码实现

///求小于n的素数个数
int countPrimes(int n) {
    vector<bool> vec(n, true);
    vec[0] = false;
    vec[1] = false;

    for (int i = 2; i < sqrt(n); i++) {
        if (vec[i]) {
            for (int j = i * i; j < n; j += i) {
                vec[j] = false;
            }
        }
    }
    return count(vec.begin(), vec.end(), true);
}

PS:时间复杂度:O(nloglogn)

二、欧拉筛选(O(n)强无敌)
=>欧拉算法是一种空间换时间的算法

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 3000001;
int prime[MAXN];//保存素数 
bool vis[MAXN];//初始化 
int Prime(int n) {
    int cnt = 0;
    memset(vis, 0, sizeof(vis));
    //筛选与Eratosthenes不同,并不是按照顺序筛选,但每一个合数都等于一个数字乘以它的最小素因子,所以遍历每个数字 i 乘以小于i(若大于i,则i为最小素因子)的所有素因子可以保证,每个合数都被遍历到
    for (int i = 2; i < n; i++) {
        if (!vis[i])
            prime[cnt++] = i;
        for (int j = 0; j < cnt && i * prime[j] < n; j++) {

            cout << "i:" << i << "  prime[j]:" << prime[j] << "  i*prime[j] : " << i * prime[j] << endl;
            vis[i * prime[j]] = true;
            if (i % prime[j] ==
                0)//关键  每一个筛选数,只被一个数乘以它的最小素因子,如果i % prime[j] == 0,则证明 i中含有prime[j]这个素因子,所以prime[j + 1] 至 prime[prime.size()-1]都不是最小素因子
                break;
        }
    }
    return cnt;//返回小于n的素数的个数
}
posted @ 2021-04-26 22:36  TCPP  阅读(119)  评论(0编辑  收藏  举报