现在的位置: 首页 > 综合 > 正文

找素数算法总结

2013年10月30日 ⁄ 综合 ⁄ 共 3529字 ⁄ 字号 评论关闭

问题描述:寻找素数 
求小于自然数N的所有素数。

解决方案

程序 1-1 经典算法

经典的素数判定算法是这样:给定一个正整数n,用2到sqrt(n)之间的所有整数去除n,如果可以整除,则n不是素数,如果不可以整除,则n就是素数。所以求小于N的所有素数程序如下:

 

#include <stdio.h>

#include <stdlib.h>

 

#define N 1000000

 

int main(int argc, char *argv[])

{

  int m, n;

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

  {

      for (m = 2; m * m <= n; m++)

           if (n % m == 0) break;

      if (m * m > n) printf("%6d",n);

  }

  system("PAUSE"); 

  return 0;

 

算法的时间复杂度是O(N*sqrt(N)),求解规模较小的输入,尚且没有问题。但对于规模较大的N,算法就力不从心了。有一种算法叫厄拉多塞筛(sieve of Eratosthenes),它在求解时具有相当高的效率,但是要牺牲较多的空间。

 

程序 1-2 厄拉多塞筛算法

这个程序的目标是,若i为素数,则设置a[i] = 1;如果不是素数,则设置为0。首先,将所有的数组元素设为1,表示没有已知的非素数。然后将已知为非素数(即为已知素数的倍数)的索引对应的数组元素设置为0。如果将所有较小素数的倍数都设置为0之后,a[i]仍然保持为1,则可判断它是所找的素数。

 

#include <stdio.h>

#include <stdlib.h>

 

#define N 1000000

 

int a[N];

 

int main(int argc, char *argv[])

{

  int i, j;

  for (i = 2; i < N; i++) a[i] = 1;

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

  {

      if (a[i])

         for (j = i + i; j < N; j += i)

             a[j] = 0;

  }

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

      if (a[i]) printf("%6d ",i);

  system("PAUSE"); 

  return 0;

}

 

例如,计算小于32的素数,先将所有数组项初始化为1(如下第二列),表示还每发现非素数的数。接下来,将索引为2、3、5倍数的数组项设置成0,因为2、3、5倍数的数是非素数。保持为1的数组项对应索引为素数(如下最右列)。

i                2       3       5       a[i]

2       1                                   1

3       1                                   1

4       1       0                         

5       1                                   1

6       1       0      

7       1                                   1

8       1       0

9       1                 0

10     1       0

11     1                                   1

12     1       0

13     1                                   1

14     1       0

15     1                 0

16     1       0

17     1                                   1

18     1       0

19     1                                   1

20     1       0

21     1                 0

22     1       0

23     1                                   1

24     1       0

25     1                          0

26     1       0

27     1                 0

28     1       0

29     1                                   1

30     1       0

31     1                                   1

 

如何理解厄拉多塞筛算法呢?

我们一定记得小学时候就学过的素数和合数的性质:任何一个合数一定可以表示成若干个素数之积。如:4 = 2 * 2,6 = 2 * 3,12 = 2 * 2 * 3。也就是说,合数N一定是小于N的某个(或若干)素数的整数倍,反之,如果N不是任何比它小的素数的倍数,则N必然是素数。

 

程序 1-3 经典算法的改进版本

经典素数判定算法中,并不需要用2到sqart(n)之间的所有整数去除n,只需要用其间的素数就够了,原因也是合数一定可以表示成若干个素数之积。算法的改进版本如下:

 

#include <stdio.h>

#include <stdlib.h>

 

#define N 1000000

 

int prime[N];

 

int main(int argc, char *argv[])

{

    int i, n, flag;

    prime[0] = 0; //保存素数的总个数

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

    {

        flag = 1;

        for (i = 1; i <= prime[0] && prime[i] * prime[i] <= n; i++)

            if (n % prime[i] == 0)

            {

                flag = 0;

                break;

            }

        if (flag)

        {       

            prime[0]++;

            prime[prime[0]] = n;

            printf("%6d ",n);

        }

    }

    system("PAUSE");   

    return 0;

}

 

算法虽然在效率下,比先前版本有所提高,但需要牺牲空间记住已确定的素数。

 

程序 1-4 厄拉多塞筛算法的改进版

程序1-2使用一个数组来包含最简单的元素类型,0和1两个值,如果我们使用位的数组,而不是使用整数的数组,则可获得更高的空间有效性。

 

#include <stdio.h>

#include <stdlib.h>

 

#define N 1000000

#define BITSPERWORD 32 

#define SHIFT 5

#define MASK 0x1F

#define COUNT 1+N/BITSPERWORD           //Bit i 对映数i

 

void set(int a[],int i);

void clr(int a[],int i);

int test(int a[],int i);

 

int  a[COUNT];

 

int main(int argc, char *argv[])

{

  int i, j;

  for (i = 0; i < COUNT; i++) a[i] = -1;

  for (i = 2; i < N; i++) {

      if (test(a,i))

         for (j = i + i; j < N; j += i)

             clr(a,j);

  }

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

      if (test(a,i)) printf("%4d ",i);

  system("PAUSE"); 

  return 0;

}

 

void set(int a[],int i) {

    a[i >> SHIFT] |= (1<<(i & MASK));

}

 

void clr(int a[],int i) {

    a[i >> SHIFT] &= ~(1<<(i & MASK));

}

 

int test(int a[],int i) {

    return a[i >> SHIFT] & (1<<(i & MASK));

}

 

 

【上篇】
【下篇】

抱歉!评论已关闭.