首页 > 其他分享 >区间质数搜索——埃拉托斯特尼筛法和欧拉筛法

区间质数搜索——埃拉托斯特尼筛法和欧拉筛法

时间:2024-09-25 20:00:54浏览次数:1  
标签:斯特尼 java 筛法 标记 质数 primes 合数

参考资料

【中国大学生计算机设计大赛国赛二等奖微课与教学辅助《埃拉托斯特尼筛法》】
【中国大学生计算机设计大赛《素数筛选—欧拉线性筛选法详解》】
Eratosthenes筛法-CSDN博客
【算法/数论】欧拉筛法详解:过程详述、正确性证明、复杂度证明-CSDN博客
水平有限,欢迎交流!

练习题

[编程入门]筛选 N 以内的素数 - C 语言网 (dotcpp. Com)

埃拉托斯特尼筛法算法

思想

步骤

埃拉托斯特尼筛法的基本步骤如下:

  1. 创建一个列表:创建一个从2到n的数字列表。
  2. 标记质数:从列表的第一个数(即2)开始,把它标记为质数。
  3. 筛掉倍数:然后去掉列表中所有2的倍数(除了2本身),因为这些数都是合数。
  4. 移动到下一个未标记的数:接下来,移动到列表中未被标记为合数的下一个数(此时是3),再次标记为质数,并筛掉它的所有倍数。
  5. 重复步骤:重复上述过程,直到根号 n。

优化

代码实现(以 java 为例)

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
    /** 优化埃氏筛法求质数
     * 获取小于等于n的所有质数
     * @param n 最大检查范围
     * @return 返回小于等于n的所有质数的列表
     */
    public static List<Integer> getPrimesBySieve(int n) {
        boolean[] st = new boolean[n + 1];
        List<Integer> primes = new ArrayList<>();
        for (int p = 2; p * p <= n; p++) {
            if (!st[p]) {  // 如果p还没有被标记,则它是质数
                primes.add(p);
                for (int i = p * p; i <= n; i += p) {
                    // 从p的平方开始,依次标记p的倍数
                    st[i] = true;  // 标记p的倍数为合数
                }
            }
        }
        // 添加剩余的大于sqrt(n)的质数
        for (int p = (int)Math.sqrt(n) + 1; p <= n; p++) {
            if (!st[p]) {
                primes.add(p);
            }
        }
        return primes;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        List<Integer> primes = getPrimesBySieve(n);
        for (Integer i : primes) {
            System.out.println(i);
        }
    }
}

欧拉筛法算法思想

思想

欧拉筛法(Euler Sieve)作为一种算法来找出所有小于或等于 n 的质数。欧拉筛法是一种改进的素数筛选法,使得每个合数只由其最小的质因数,它减少了标记合数时的重复工作,提高了效率。

步骤

下面是该方法的步骤归纳:

  1. 初始化:
    • 创建一个布尔数组 st,长度为 n+1,用于标记数字是否为合数
    • 创建一个列表 primes 来存储筛选出的质数。
  2. 遍历从 2 到 n 的所有整数:
    • 对于每一个整数 i,如果 st[i]false(即 i 未被标记为合数),则认为 i 是一个质数,并将 i 添加到质数列表 primes 中。
  3. 标记合数:
    • 使用已经找到的质数列表中的元素 p 来标记合数。对于每一个质数 p,遍历从 i*p 开始的后续合数,并将其在 st 数组中标记为 true
    • 在标记合数的过程中,一旦 i*p 超过 n,则停止进一步的标记。
    • 另外,当 i 能够被 p 整除时(即 i % p == 0),表明 p为p * i的最小质因子,此时可以停止内部循环以避免重复标记。
  4. 返回结果:
    • 完成以上步骤后,返回包含所有质数的列表 primes
      这种筛法的关键在于减少对合数的重复标记次数,使得每个合数只由其最小的质因数来标记一次,从而提高了算法效率。

代码实现(以 java 为例)

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
    public static List<Integer> getPrimesByEulerSieve(int n) {
        boolean[] st = new boolean[n + 1];  // 判断是否是合数
        List<Integer> primes = new ArrayList<>();  // 存储找到的质数
        for (int i = 2; i <= n; i++) {
            if (!st[i]) {  // 如果i没有被标记为合数,则i是质数
                primes.add(i);  // 将i添加到质数列表中
            }
            for (Integer p : primes) {
                if(i*p>n)//越界
                    break;
                st[i * p] = true;  // 标记合数
                /*
                 * 确保每个合数只被它最小的质因数筛除一次
                 * 条件成立此时p为p*i的最小质因子
                 * 如合数12 当发现能被2筛去(12 = 2*6)时,此时终止循环,否则会发现仍会被3筛去(12 = 3*4)
                 */
                if (i % p == 0)
                    break;
            }
        }
        return primes;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        List<Integer> primes = getPrimesByEulerSieve(n);
        for (Integer i : primes) {
            System.out.println(i);
        }
        sc.close();
    }
}

标签:斯特尼,java,筛法,标记,质数,primes,合数
From: https://www.cnblogs.com/qinLiCode/p/18432084

相关文章

  • 筛质数(线性筛法--进阶版)(面对大部分都直接ac)
    给定一个正整数 n,请你求出 1∼n中质数的个数。输入格式共一行,包含整数 n。输出格式共一行,包含一个整数,表示 1∼n中质数的个数。数据范围1≤n≤10^6输入样例:8输出样例:4思路:给一个数:将质数筛到的同时,筛去它的倍数,并且该倍数一定是在给定的数内的这样在下次......
  • 判断质数(小白秒懂版本)短时间记忆二分模板
    给定 n个正整数 ai,判定每个数是否是质数。输入格式第一行包含整数 n。接下来 n 行,每行包含一个正整数 ai。输出格式共 n行,其中第 i行输出第 i个正整数 ai是否为质数,是则输出 Yes,否则输出 No。数据范围1≤n≤100,1≤ai≤231−1输入样例:226输出样例:Yes......
  • 筛法求素数
    筛法求素数Eratosthenes筛法时间复杂度\(O(nloglogn)\)。关键优化:\(j\)从\(i\timesi\)开始voidgetprime(intmx){ memset(is_prime,1,sizeof(is_prime)); is_prime[0]=is_prime[1]=0; F(i,2,mx){ if(is_prime[i]){ prime[++cnt]=i;//存 if(1ll......
  • 信息学奥赛初赛天天练-92-CSP-S2023阅读程序2-动态数组、反转函数、埃氏筛法、欧拉筛
    2023CSP-S阅读程序2判断题正确填√,错误填⨉;除特殊说明外,判断题1.5分,选择题3分,共计40分)01#include<iostream>02#include<cmath>03#include<vector>04#include<algorithm>05usingnamespacestd;0607longlongsolve1(intn){08vector<bo......
  • 信息学奥赛初赛天天练-92-CSP-S2023阅读程序2-动态数组、反转函数、埃氏筛法、欧拉筛
    2023CSP-S阅读程序2判断题正确填√,错误填⨉;除特殊说明外,判断题1.5分,选择题3分,共计40分)01#include<iostream>02#include<cmath>03#include<vector>04#include<algorithm>05usingnamespacestd;0607longlongsolve1(intn){08vector<boo......
  • 一个线性筛的多功能组合:筛法求质数+约数个数+约数和
    F:\BC\2024\9>main1活动代码页:9362 2X2=43 3X2=6 3X3=94X2=85 5X2=10 5X3=15 5X5=256X2=127 7X2=14 7X3=21 7X5=35 7X7=498X2=169X2=18 9X3=2710X2=2011 11X2=22 11X3=33 11X5=55 11X7=77 11X11=12112X2=2413 13X2=26 13X......
  • 「数学::质数」埃氏筛|欧拉筛(埃拉托斯特尼筛法|线性筛法)/ LeetCode 204(C++)
    目录概述1.埃氏筛思路复杂度Code2.欧拉筛(线性筛)思路复杂度Code总结概述上一节我们介绍了对判断一个数是否为质数的方法:「数学::质数」试除法/LuoguP5736(C++)那如果我们期望输出一个范围内的所有质数,使用试除法的时间复杂度是n√n,怎么办呢?LeetCode204:给定整......
  • 【AcWing】866~868. 质数
    #include<iostream>#include<math.h>usingnamespacestd;intn;boolis_prime(intx){if(x<2)returnfalse;for(inti=2;i<=x/i;i++){if(x%i==0)returnfalse;}returntrue;}intmain(){cin>>n;......
  • 找质数完整版?(小白的练习)
    目的很简单,学到哪就稍微用一下刚学的知识,下面是我的代码(其中有些步骤可以简化,就比如在search函数中用指针没什么意义,因为我只需要return“tureorfalse”如果用指针其实是杀鸡用牛刀,不过只是练习一下学的,所以目的不同代码自然不同,欢迎指教#include#includevoidsearch(int......
  • 质数
    1.质数定义我们这样定义质数:如果自然数$p>1$的因数只有1和它本身,那么$p$是质数。不是质数,就是合数。质数有很多美妙的性质,比如:如果一个数是质数,那么它是自然数。如果一个数是质数,那么它不是合数。如果一个数是质数,那么它大于等于2。2.判断\(n\)是否为质数的方法2.1枚......