posts - 73,  comments - 55,  trackbacks - 0

1。自然数是0,1,2……
2。素数是2,3,5……(不包括1的只能背1和它本身整除的自然数)

import java.util.Scanner;

public class Prime {

    //最基本的做法

    private int prime1(int num) {
        int i = 0, s = 0;
        label1: for (int n = 2; n <= num; n++) {
            for (int m = 2; m * m <= n; m++) {
                if (n % m == 0)
                    continue label1;
            }
            s++;
            i++;
            //System.out.println("第" + i + "个素数是:" + n);
        }
        return s;
    }

    //6N±1法

    private int prime2(int num){
        int i = 0, s = 0;
        for(int n = 2; n <=3; n ++){
            s++;
            i++;
            //System.out.println("第" + i + "个素数是:" + n);
        }
        label1: for(int n = 1; ; n++) {
            label2: for (int m = 0; m <= 1; m++) {
                int tmp = 2 * (3 * n + m) - 1;
                if (tmp > num)
                    break label1;
                for(int k = 2; k * k <= tmp; k++)
                    if (tmp % k == 0)
                        if (m == 0)
                            continue label2;
                        else
                            continue label1;
                s++;
                i++;
                //System.out.println("第" + i + "个素数是:" + tmp);
            }
        }
        return s;
    }

    public static void main(String args[]) {
        Scanner in = new Scanner(System.in);
        int num = in.nextInt();
        long start = System.currentTimeMillis();
        int sum = new Prime().prime1(num);
        long end = System.currentTimeMillis();
        System.out.println("方法一共" + sum + "个素数");
        System.out.println("用时:" + (end - start));
        start = System.currentTimeMillis();
        sum = new Prime().prime2(num);
        end = System.currentTimeMillis();
        System.out.println("方法二共" + sum + "个素数");
        System.out.println("用时:" + (end - start));
       
    }
}

输入:1000000

运行结果:

方法一共78498个素数
用时:3434
方法二共78498个素数
用时:3453

(看来基本方法比6N±1法还要更快些,奇怪了,我的程序写的没什么问题阿)


【1】求10000以内的所有素数。
素数是除了1和它本身之外再不能被其他数整除的自然数。由于找不到一个通项公式来表示所有的素数,所以对于数学家来说,素数一直是一个未解之谜。像著名的 哥德巴赫猜想、孪生素数猜想,几百年来不知吸引了世界上多少优秀的数学家。尽管他们苦心钻研,呕心沥血,但至今仍然未见分晓。
自从有了计算机之后,人们借助于计算机的威力,已经找到了2216091以内的所有素数。
求素数的方法有很多种,最简单的方法是根据素数的定义来求。对于一个自然数N,用大于1小于N的各个自然数都去除一下N,如果都除不尽,则N为素数,否则N为合数。
但是,如果用素数定义的方法来编制计算机程序,它的效率一定是非常低的,其中有许多地方都值得改进。
第一,对于一个自然数N,只要能被一个非1非自身的数整除,它就肯定不是素数,所以不
必再用其他的数去除。
第二,对于N来说,只需用小于N的素数去除就可以了。例如,如果N能被15整除,实际
上就能被3和5整除,如果N不能被3和5整除,那么N也决不会被15整除。
第三,对于N来说,不必用从2到N一1的所有素数去除,只需用小于等于√N(根号N)的所有素数去除就可以了。这一点可以用反证法来证明:
如果N是合数,则一定存在大于1小于N的整数d1和d2,使得N=d1×d2。
如果d1和d2均大于√N,则有:N=d1×d2>√N×√N=N。
而这是不可能的,所以,d1和d2中必有一个小于或等于√N。
基于上述分析,设计算法如下:
(1)用2,3,5,7逐个试除N的方法求出100以内的所有素数。
(2)用100以内的所有素数逐个试除的方法求出10000以内的素数。
首先,将2,3,5,7分别存放在a[1]、a[2]、a[3]、a[4]中,以后每求出一个素数,只要不大于100,就依次存放在A数组中的一个单元 中。当我们求100—10000之间的素数时,可依次用a[1]-a[2]的素数去试除N,这个范围内的素数可以不保存,直接打印。

【2】用筛法求素数。
简单介绍一下厄拉多塞筛法。厄拉多塞是一位古希腊数学家,他在寻找素数时,采用了一种与众不同的方法:先将2-N的各数写在纸上:

在2的上面画一个圆圈,然后划去2的其他倍数;第一个既未画圈又没有被划去的数是3,将它画圈,再划去3的其他倍数;现在既未画圈又没有被划去的第一个数 是5,将它画圈,并划去5的其他倍数……依次类推,一直到所有小于或等于N的各数都画了圈或划去为止。这时,表中画了圈的以及未划去的那些数正好就是小于 N的素数。

这很像一面筛子,把满足条件的数留下来,把不满足条件的数筛掉。由于这种方法是厄拉多塞首先发明的,所以,后人就把这种方法称作厄拉多塞筛法。
在计算机中,筛法可以用给数组单元置零的方法来实现。具体来说就是:首先开一个数组:a[i],i=1,2,3,…,同时,令所有的数组元素都等于下标 值,即a[i]=i,当i不是素数时,令a[i]=0 。当输出结果时,只要判断a[i]是否等于零即可,如果a[i]=0,则令i=i+1,检查下一个a[i]。
筛法是计算机程序设计中常用的算法之一。

【3】用6N±1法求素数。
任何一个自然数,总可以表示成为如下的形式之一:
6N,6N+1,6N+2,6N+3,6N+4,6N+5 (N=0,1,2,…)
显然,当N≥1时,6N,6N+2,6N+3,6N+4都不是素数,只有形如6N+1和6N+5的自然数有可能是素数。所以,除了2和3之外,所有的素数都可以表示成6N±1的形式(N为自然数)。
根据上述分析,我们可以构造另一面筛子,只对形如6 N±1的自然数进行筛选,这样就可以大大减少筛选的次数,从而进一步提高程序的运行效率和速度。

在程序上,我们可以用一个二重循环实现这一点,外循环i按3的倍数递增,内循环j为0-1的循环,则2(i+j)-1恰好就是形如6N±1的自然数。

posted on 2006-11-20 15:28 保尔任 阅读(3167) 评论(6)  编辑  收藏 所属分类: Arithmetic & Data Structure

FeedBack:
# re: 如何求素数
2007-02-18 13:30 | zero
我以前学过些c,今天开始学java,刚刚写的~^_^然后和楼主的比较了下,发现自己写得还是水了些哈哈,只有一个地方我认为做得比较好的,就是用乘法代替了开方,我估计这样会快一点点吧,嗯....,觉得满不错的有得和好的代码比较下,注了册还没验证完.我邮箱zero_002006@163.com,qq:358315553
public class Prime {
public static void main(String[] args) {
int[] prime_array = new int[10000];//用来保存10万以下的质数(共9592个)
prime_array[0]=3;
prime_array[1]=5;
int i,primeId=-1,m=2,prime;
System.out.println(2);//质数2直接打出^_^
for (int a = 3; a <= 100000; a += 2) {
if(m*m<a){
//避免使用sqrt()
m++;
}
for (i=0;(prime=prime_array[i])<=m;i++) {
if (a % prime == 0) {
break;
}
}
if (prime>m) {
prime_array[++primeId]=a;
System.out.print(a+" ");
}
}
for(int a = 100001; a <= 1000000000; a += 2){
if(m*m<a){
//避免使用sqrt()
m++;
}
for (i=0;(prime=prime_array[i])<=m;i++) {
if (a % prime == 0) {
break;
}
}
if (prime>m) {
++primeId;
System.out.print(a+" ");
}
}
System.out.println("\n十亿下共"+(primeId+2)+"个质数.");
}
}
  回复  更多评论
  
# re: 如何求素数[未登录]
2007-11-19 20:28 | yuyu
Module Module1

Sub Main()
Dim n, i As Long
Dim k As Integer
Dim a As Integer = 1
For n = 1 To 100000 Step 2
k = 1 'k是作为一个标志量
For i = 2 To Int(Math.Sqrt(n))
If n Mod i = 0 Then
k = 0 '当k为0时,说明n不是质数
Exit For
End If
Next
If k = 1 Then '当k为1时,说明没有执行k=0这一小循环
a += 1 'a计录质数的个数
Console.Write(" " & n & " " & a)

End If

Next
  回复  更多评论
  
# 用VB.NET求质数[未登录]
2007-11-19 21:03 | yuyu
Module Module1

Sub Main()
Dim n, i As Long
Dim k As Integer
Dim a As Integer = 1
For n = 1 To 100000 Step 2
k = 1 'k是作为一个标志量
For i = 2 To Int(Math.Sqrt(n))
If n Mod i = 0 Then
k = 0 '当k为0时,说明n不是质数
Exit For
End If
Next
If k = 1 Then '当k为1时,说明没有执行k=0这一小循环
a += 1 '用a计录质数的个数
Console.Write(" " & n & " " & a)
End If
Next
End Sub

End Module  回复  更多评论
  
# re: 如何求素数[未登录]
2007-11-30 15:38 | caroline
奇怪第一个代码,为什么用m*m<=n呢  回复  更多评论
  
# re: 如何求素数
2011-06-24 13:44 | bdpgc
你是编程高手  回复  更多评论
  
# re: 如何求素数[未登录]
2012-05-16 18:48 | javaer
其中楼主的时间太长了,我用筛选法,算1千万里有多少素数,耗时500多ms, 1百万以内耗时20ms不到,不包括数据打印时间。

参考:
http://lg-asus.iteye.com/blog/1463612  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
 

<2007年11月>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

常用链接

留言簿(4)

随笔分类

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜