zoukankan      html  css  js  c++  java
  • [原]素数筛法【Sieve Of Eratosthenes + Sieve Of Euler】

    拖了有段时间,今天来总结下两个常用的素数筛法:

    1、sieve of Eratosthenes【埃氏筛法】

    这是最简单朴素的素数筛法了,根据wikipedia,时间复杂度为 O(n loglog n),空间复杂度为O(n)。

    算法思想:先假定所有的数都是素数,然后从最小的素数2出发,把素数的所有倍数筛出去。又因为一个数的质因数都是成对出现的,比如100 = 1*100 = 2*50 = .....= 10*10,所以筛素数时只用筛到 n的开平方就行了。

    伪代码如下:


    对于任意的范围n,

    设bool prime[ ],初始化 2→n 的元素为false,

    for(i=2; i < sqrt(n); i+++)

       if (!prime[ i ])

          for(j = i*i;  j * i < n; j+=i)

               prime[ j ] = false

    2、sieve of Euler【欧拉线性筛】

    尽管把埃氏筛法“优化”到n的开平方,但是还是做了很多重复的工作,比如 合数 6,它就会被2,和3重复筛出。

    根据“每个整数都可以分解成它的 质因数之积”,因此每个数只需要被它的最小质因数筛除。

    由上可以得到线性时间复杂度的筛法,欧拉筛法。

    算法思路:

    欧拉筛是个以空间换时间的算法,用prime[ ]数组记录素数,初始bool数组is_prime[ ]为false记录每个数是否是素数,

    伪代码如下:

    k = 0

    for(i = 2; i < n; i++)

        if(!is_prime[i])

          prime[k++] = i

       for(j = 0; j < k&&i * prime[ j ]; j++)

          is_prime[i*prime[ j ]] = true;

         if(i % prime[ j ]) break;    //关键步骤。在此的prime[ j ]一定是i的最小质因子,you can gusse why~0-0

      【以下是实现代码,外加两种算法在时间上的比对】

    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cstring>
    using namespace std;
    const long long maxn = 100000000;
    bool  is_prime[maxn];
    int EUprime[maxn];
    bool ERprime[maxn];
    
    int euler(int n){
       int k = 0;
       memset(is_prime,false, sizeof(is_prime));
       for(int i = 2; i <= n; i++){
        if(!is_prime[i])
            EUprime[k++] = i;
        for(int j = 0; j < k&&i * EUprime[j] <= n; j++){
            is_prime[i*EUprime[j]] = true;
            if(i % EUprime[j] == 0) break;
        }
       }
       return k;
    }
    
    int eratosthense(int n){
        int k = 0;
        memset(ERprime,false,sizeof(ERprime));
        for(int i = 2; i * i <= n; i++){
            if(!ERprime[i]){
                for(int j = i*i; j <= n; j+=i){
                    ERprime[j] = true;
                }
            }
        }
        for(int i = 2; i <= n; i++)
        if(!ERprime[i]) {k++;}
        return k;
    }
    
    int main(){
        //int n;
        clock_t st,ed;
        double sec;
        for(int i = 10; i < 1000000000; i *= 10){
          cout<<i<<":"<<endl;
            int res;
            st = clock();
            res = eratosthense(i);
            ed = clock();
            sec = (double)(ed - st) / (double) CLOCKS_PER_SEC;
            printf("eratosthense :		%8d	%.8lf
    ", res, sec);
    
            st = clock();
            res = euler(i);
            ed = clock();
            sec = (double)(ed - st) / (double) CLOCKS_PER_SEC;
            printf("Euler :		%16d	%.8lf
    ", res, sec);
    
        }
    }
    


    【可以看到在小数据上两个算法效率差别不大,在大数据情况下,Euler筛法的效率明显比埃氏筛法高】


    作者:u011652573 发表于2014-3-25 16:55:24 原文链接
    阅读:44 评论:0 查看评论
  • 相关阅读:
    设计模式(二)装饰器模式
    AppManager
    判断用户是否已经登录
    RecyclerView 下拉刷新和加载更多
    Android Application中的Context和Activity中的Context的异同
    Android中通过反射获取资源Id
    Android解析WindowManager(一)WindowManager体系
    设计模式(二)模板方法模式
    staticmethod
    反射
  • 原文地址:https://www.cnblogs.com/ZiningTang/p/3834756.html
Copyright © 2011-2022 走看看