我的Java开发学习之旅------>求N内所有的素数

一、素数的概念

质数(prime number)又称素数,有无限个。一个大于1的自然数,除了1和它本身外,不能被其他自然数(质数)整除,换句话说就是该数除了1和它本身以外不再有其他的因数;否则称为合数

根据算术基本定理,每一个比1大的整数,要么本身是一个质数,要么可以写成一系列质数的乘积;而且如果不考虑这些质数在乘积中的顺序,那么写出来的形式是唯一的。最小的质数是2

二、算法

算法1. 

开根号法:如果一个数(>2),对这个数求平方根,如果这个数能被这个数的平方根到2之间的任何一个(只要有一个就行)整除说明就不是质数,如果不能就说明是质数!

原理:假如一个数N是合数,它有一个约数a,a×b=N,则a、b两个数中必有一个大于或等于根号N,一个小于或等于根号N。因此,只要小于或等于根号N的数(1除外)不能整除N,则N一定是素数。

	public void zhishu(int num) {
		int i, j, k;
		for (i = 2; i < num; i++) {
			k = (int) Math.sqrt(i);
			for (j = 2; j <= k; j++) {
				if(i%j==0){
					break;
				}
			}
			if (j>k) {
				System.out.println("素数: "+i);
			}
		}
	}

算法2.埃拉托斯特尼素数筛选法

要得到自然数n以内的全部素数,必须把不大于



的所有素数的倍数剔除,剩下的就是素数。

给出要筛数值的范围n,找出以内的素数。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个质数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个质数5筛,把5留下,把5的倍数剔除掉;不断重复下去......。

步骤

详细列出算法如下:

  1. 列出2以后的所有序列:

    • 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  2. 标出序列中的第一个素数,也就是2,序列变成:
    • 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
  3. 将剩下序列中,划掉2的倍数,序列变成:
    • 2 3 5 7 9 11 13 15 17 19 21 23 25
  4. 如果现在这个序列中最大数小于最后一个标出的素数的平方,那么剩下的序列中所有的数都是素数,否则回到第二步。
  5. 本例中,因为25大于2的平方,我们返回第二步:
  6. 剩下的序列中第一个素数是3,将主序列中3的倍数划掉,主序列变成:
    • 2 3 5 7 11 13 17 19 23 25
  7. 我们得到的素数有:2,3
  8. 25仍然大于3的平方,所以我们还要返回第二步:
  9. 现在序列中第一个素数是5,同样将序列中5的倍数划掉,主序列成了:
    • 2 3 5 7 11 13 17 19 23
  10. 我们得到的素数有:2,3,5 。
  11. 因为23小于5的平方,跳出循环.

结论:2到25之间的素数是:2 3 5 7 11 13 17 19 23。

下面代码摘自网络

	public static void getPrimes(int n) {
		if (n < 2 || n > 9999999) // 之所以限制最大值为9999999万,是因为JVM内存限制,当然有其他灵活方案可以绕过(比如位图法)
			throw new IllegalArgumentException("输入参数n错误!");

		int[] array = new int[n]; // 假设初始所有数都是素数,且某个数是素数,则其值为0;比如第一个数为素数那么array[0]为0
		array[0] = 1; // 0不是素数
		array[1] = 1; // 1不是素数
		// 下面是筛选核心过程
		for (int i = 2; i < Math.sqrt(n); i++) { // 从最小素数2开始
			if (array[i] == 0) {
				for (int j = i * i; j < n; j += i) {
					array[j] = 1; // 标识该位置为非素数
				}
			}
		}

		// 打印n以内的所有素数,每排10个输出
		System.out.println(n + "以内的素数如下: ");
		int count = 0; // 当前已经输出的素数个数
		int rowLength = 10; // 每行输出的素数个数
		for (int i = 0; i < array.length; i++) {
			if (array[i] == 0) {
				if (count % rowLength == 0 && count != 0) {
					System.out.println();
				}
				count++;

				System.out.print(i + "\t");
			}
		}
	}

用以上两个算法求9999999的所有素数

开根号法用时:21507毫秒

埃拉托斯特尼素数筛选法用时: 6658毫秒

关于算法,以下几个用C实现的先mark下来。

http://blog.chinaunix.net/uid-26548237-id-3364131.html

超高速计算n以内素数个数(百亿内3毫秒解决)

http://blog.csdn.net/jianxia_wzx/article/details/8663759

==================================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址:http://blog.csdn.net/ouyang_peng

==================================================================================================

时间: 2024-09-28 21:14:16

我的Java开发学习之旅------&gt;求N内所有的素数的相关文章

我的Java开发学习之旅------&amp;gt;求字符串中出现次数最多的字符串以及出现的次数

金山公司面试题:一个字符串中可能包含a~z中的多个字符,如有重复,如String data="aavzcadfdsfsdhshgWasdfasdf",求出现次数最多的那个字母及次数,如有多个重复的则都求出. 此题的解题思路如下: 引入TreeSet:通过集合快速找到所有出现过的字符串 引入ArrayList:为了快速排序,再通过StringBuffer生成排序后的字符串 通过String的indexOf方法和lastIndexOf方法来计算每个字符串出现的次数最大值 使用HashMap

我的Java开发学习之旅------&amp;gt;Java字符编码解析

Java开发中,常常会遇到乱码的问题,一旦遇到这种问题,常常就很扯蛋,每个人都不愿意承认是自己的代码有问题.其实编码问题并没有那么神秘,那么不可捉摸,搞清Java的编码本质过程就真相大白了.               其实,编码问题存在两个方面:JVM之内和JVM之外.   1.Java文件编译后形成class 这里Java文件的编码可能有多种多样,但Java编译器会自动将这些编码按照Java文件的编码格式正确读取后产生class文件,这里的class文件编码是Unicode编码(具体说是UT

我的Java开发学习之旅------&amp;gt;Java经典面试题

摘自张孝祥itcast 从享受生活的角度上来说:"程序员并不是一种最好的职业,我认为两种人可以做程序员,第一,你不做程序员,你就没有什么工作可做,或者说是即使有可以做的工作但是你非常不愿意去做:第二,你非常痴迷和爱好程序,并且在这方面有一些天赋和优势.程序员的结局也是有两种:第一,默默退休,第二以程序员为起点或跳板,注意积累,跟对了好的老板或团队,找到和很好的搭档自己创业,成为IT金领和富翁." 人们在时间面前是平等的,吾生也有涯,所以,你的经验更丰富点,那不算什么,经验是用时间积累的

我的Java开发学习之旅------&amp;gt;工具类:Java获取字符串和文件进行MD5值

ps:这几天本人用百度云盘秒传了几部大片到云盘上,几个G的文件瞬秒竟然显示"上传成功"!这真让我目瞪口呆,要是这样的话,那得多快的网速,这绝对是不可能的,也许这仅是个假象.百度了一下才发现所谓的"秒传"是常见的"忽略式"上传方式,就是您上传了一个文件名为111.exe,MD5为一个数,有一个网友以前也上传一个叫222.exe,MD5和您上传的文件MD5码一模一样,所以这个文件上传到服务器上的时间就很短了,这是因为别人上传过这个文件,您上传这个文件

我的Java开发学习之旅------&amp;gt;Java双重检查锁定及单例模式详解(转)

简介:          所有的编程语言都有一些共用的习语.了解和使用一些习语很有用,程序员们花费宝贵的时间来创建.学习和实现这些习语.问题是,稍后经过证明,一些习语并不完全如其所声称的那样,或者仅仅是与描述的功能不符.在 Java 编程语言中,双重检查锁定就是这样的一个绝不应该使用的习语.在本文中,Peter Haggar 介绍了双重检查锁定习语的渊源,开发它的原因和它失效的原因.         单例创建模式是一个通用的编程习语.和多线程一起使用时,必需使用某种类型的同步.在努力创建更有效的

我的Java开发学习之旅------&amp;gt;Java ClassLoader解析一(转)

jvm classLoader architecture: Bootstrap ClassLoader/启动类加载器  主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作. Extension ClassLoader/扩展类加载器  主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作. System ClassLoader/系统类加载器  主要负责java -c

我的Java开发学习之旅------&amp;gt;Java ClassLoader解析二(转)

一.什么是ClassLoader?          大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法,如果另外一个文件不存在的,则会引发系统异常.而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需

我的Java开发学习之旅------&amp;gt;交通灯管理系统

1.交通灯管理系统的项目需求 模拟实现十字路口的交通灯管理系统逻辑,具体需求如下: Ø         异步随机生成按照各个路线行驶的车辆. 例如: 由南向而来去往北向的车辆 ---- 直行车辆        由西向而来去往南向的车辆 ---- 右转车辆        由东向而来去往南向的车辆 ---- 左转车辆        ... Ø         信号灯忽略黄灯,只考虑红灯和绿灯. Ø         应考虑左转车辆控制信号灯,右转车辆不受信号灯控制. Ø         具体信号灯控制

我的Java开发学习之旅------&amp;gt;JAVA IO 设计模式彻底分析

本文转载于网络. 一.引子(概括地介绍Java的IO) 无论是哪种编程语言,输入跟输出都是重要的一部分,Java也不例外,而且Java将输入/输出的功能和使用范畴做了很大的扩充.它采用了流的 机制来实现输入/输出,所谓流,就是数据的有序排列,而流可以是从某个源(称为流源或Source of Stream)出来,到某个目的地(称为流汇或Sink of Stream)去的.由流的方向,可以分成输入流和输出流,一个程序从输入流读取数据向输出流写数据. 如,一个程序可以用FileInputStream类