【问题标题】:generating k prime numbers using Sieve of Eratosthenes使用埃拉托色尼筛法生成 k 个素数
【发布时间】:2015-10-08 07:36:47
【问题描述】:

浏览了一些实现,发现,想知道为什么从 k = m * m 开始迭代是安全的?谢谢。

http://www.algolist.net/Algorithms/Number_theoretic/Sieve_of_Eratosthenes

public void runEratosthenesSieve(int upperBound) {
      int upperBoundSquareRoot = (int) Math.sqrt(upperBound);
      boolean[] isComposite = new boolean[upperBound + 1];
      for (int m = 2; m <= upperBoundSquareRoot; m++) {
            if (!isComposite[m]) {
                  System.out.print(m + " ");
                  for (int k = m * m; k <= upperBound; k += m)
                        isComposite[k] = true;
            }
      }
      for (int m = upperBoundSquareRoot; m <= upperBound; m++)
            if (!isComposite[m])
                  System.out.print(m + " ");
}

【问题讨论】:

    标签: java algorithm primes


    【解决方案1】:

    每个小于 m*m 且 m 是因数的合数,例如。 m*n,具有比 m 小的因子,例如。 n,我们已经将其标记为复合。

    这适用于素数或合数n,对于素数n,我们在m=n时的循环中设置。

    对于复合 n:我们知道任何大于 1 的整数都可以表示为素数的乘积。这些质因数之一是 n 的最小质因数,我们称之为 s。由于 s 是 n 的质因数,我们可以将 n 表示为 s*r,对于一些 r。这也意味着 m*n 是 m*s*r。 s

    【讨论】:

    • 我认为在这种情况下,只要 n 是素数,就会评估 n * m?或者任何 n 是(复合或素数)?
    • 如果 n 是复合的,那么当使用 n 的最小素因子时,n * m 将被标记。
    • Thanks moreON,你的意思是假设 n = pow (p1, x1) * pow (p2, x2),p1 和 p2 都是
    • 我已经编辑为复合 n 提供更一般的解释。
    【解决方案2】:

    让我们取一个数字并分解它:例如。 120

    • 1 x 120
    • 2 x 60
    • 3 x 40
    • 4 x 30
    • 5 x 24
    • 6 x 20
    • 8 x 15
    • 10 x 12

    现在,一个观察结果:sqrt(120) = 11(发言)

    现在,下一个观察,each of the above factors have one thing in common, ie. one of the factors is less than 11 and other is greater than 11

    现在让我们分解 36:

    • 1 x 36
    • 2 x 18
    • 3 x 12
    • 4 x 9
    • 6 x 6

    和 sqrt(36) = 6。同样我们可以做一个类似的观察,每个因子都有一个小于 6 的数字和其他更大的数字,除了 6 x 6,因为 36 是一个正方形。

    所以,我们可以很容易地推断出:

    对于任何数字,如果它不是质数,我们总是可以找到(至少)它的一个因子,如果我们去它的平方根。

    因此,为了降低复杂性,我们需要对范围内的每个数字求平方根,因此,sqrt(upperBound) 足以用于外循环。那是因为,如果到那时任何数字都没有被标记为合数,那永远不会是因为我们已经考虑了所有可能的除数。

    编辑:

    另外,这种筛子的实现不是most optimized 可以的。不是在渐近复杂度方面,但你可以做一些事情来减少一些操作。我将在 C++ 中添加我的 sieve 实现,它计算所有素数直到 MAX。

    #define MAX 1000000
    #define I int
    #define FOR(i,a,b) for(i=a;i<b;i++)
    I p[MAX]={1,1,0};            //global declaration
    I prime[MAX/10]={2};         //global declaration
    void sieve()
    {
        I i,j,k=1;
        for(i=3;i*i<=MAX;i+=2)
        {
            if(p[i])
                continue;
            for(j=i*i;j<MAX;j+=2*i)
                p[j]=1;
        }
        for(i = 3; i < MAX; i+=2)
        {
            if(!p[i])
                prime[k++]=i;
        }
        return;
    }
    

    【讨论】:

    • 我认为问题实际上是在询问设置 iscomposite 标志的迭代从哪里开始(每次迭代从 m*m 开始,而不是简单地从 m 开始),而不是我们如何知道我们'已经做了足够多的事情来确保一个数字是素数。
    • 质数将大于 sqrt(n),但在外循环超出 sqrt(n) 后不需要标记它们。 (n = upperBound),因为 sqrt(n) 之上的所有合数都已被标记。所以,它们都是浪费的迭代。
    • 这显然意味着,如果任何高于 sqrt(n) 的数字没有被标记,它是一个素数
    • 这是因为,对于每个合数,我们至少有一个我们已经遇到过的因数。 (因为至少一个因素将低于 sqrt(n) )。因此,那个因素肯定会将该数字标记为复合数字(通过内部循环)。如果一个数字没有被任何数字标记为复合,它是一个素数
    • 如果你考虑一个合数 a*b,其中 a >= b >= n,那么显然 a*b >= n*n。因此,任何具有一对因子且两者都大于 n 的数明显高于 n*n,因此任何小于 n*n 的数要么是素数,要么至少有一个因子小于 n。
    猜你喜欢
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2011-12-16
    • 2017-11-14
    • 1970-01-01
    相关资源
    最近更新 更多