Java遍历质数的算法优化

小白初学,还请大佬多多指教。
质数概念
质数即素数,是只能被1和它本身整除的自然数。

以遍历十万以内的质数为例逐步进行算法优化:

  • 算法一:
class PrimeNumberTest{
	public static void main(String[] args){
		long start = System.currentTimeMillis();
		boolean isFlag = true;//标识i是否被j除尽过,一旦除尽,修改其值
		for(int i=2; i<=100000; i++){//遍历100000以内的自然数
			//boolean isFlag = true;//标识i是否被j除尽过,一旦除尽,修改其值
			for(int j=2; j<i; j++){//j:被i去除
				if(i%j == 0){//i被j除尽
					isFlag = false;
				}
			}
			if(isFlag){
				System.out.println(i);
			}
			//重置isFlag
			isFlag = true;
		}
		long end = System.currentTimeMillis();
		System.out.println("程序执行时间:" + (end - start));
	}
}

相比于遍历奇数偶数来说,遍历质数的难点在于一次循环不能确定一个数是不是质数,必须经过嵌套循环完成之后才可以确定,因此引入一个布尔型变量isFlag,用来标识遍历的结果状态。其中如果把isFlag的声明放在一层循环以内,这样虽然可以简化几行代码,但是过多地消耗了内存,有点得不偿失。
这种方式可以实现遍历,但效率极低

  • 算法二:
class PrimeNumberTest{
	public static void main(String[] args){
		long start = System.currentTimeMillis();
		boolean isFlag = true;//标识i是否被j除尽过,一旦除尽,修改其值
		for(int i=2; i<=100000; i++){//遍历100000以内的自然数
			//boolean isFlag = true;//标识i是否被j除尽过,一旦除尽,修改其值
			for(int j=2; j<i; j++){//j:被i去除   
				if(i%j == 0){//i被j除尽
					isFlag = false;
					break;//优化一:只对本身非质数的自然数是有效的。只要有一个被除尽就不是质数了,就不需要往下执行了
				}
			}
			if(isFlag){
				//System.out.println(i);
			}
			//重置isFlag
			isFlag = true;
		}
		long end = System.currentTimeMillis();
		System.out.println("程序执行时间:" + (end - start));
	}
}

算法二对算法一进行了第一步优化,当判定一个数是质数时,做两个工作,一是修改结果状态标识,二是终止内层循环,这样可以大大减少遍历次数。

  • 算法三:
class PrimeNumberTest{
	public static void main(String[] args){
		long start = System.currentTimeMillis();
		boolean isFlag = true;//标识i是否被j除尽过,一旦除尽,修改其值
		for(int i=2; i<=100000; i++){//遍历100000以内的自然数
			//boolean isFlag = true;//标识i是否被j除尽过,一旦除尽,修改其值
			for(int j=2; j<=Math.sqrt(i); j++){//j:被i去除   优化二
				if(i%j == 0){//i被j除尽
					isFlag = false;
					break;//优化一:只对本身非质数的自然数是有效的。只要有一个被除尽就不是质数了,就不需要往下执行了
				}
			}
			if(isFlag){
				System.out.println(i);
			}
			//重置isFlag
			isFlag = true;
		}
		long end = System.currentTimeMillis();
		System.out.println("程序执行时间:" + (end - start));
	}
}

在这里插入图片描述
该算法使用Math.sqrt()方法,这个方法用来求解一个数的平方根,我们都知道,一个数等于它的平方根的乘积,如上图:
i = Math.sqrt(i) * Math.sqrt(i)
假设 y 小于 Math.sqrt(i) ,如果 i = x*y , 那么 x 一定大于 Math.sqrt(i)
当我们循环遍历时,只需要遍历到 Math.sqrt(i) 即可,因为我们从2开始遍历时,到 Math.sqrt(i) ,如果这个数不是质数,在2到 Math.sqrt(i) 这个区间内一定存在一个数 y 使得 i = x*y ,这样就能断定这时的 i 一定不是质数,因为 y 既不是1也不是i。
通过这种算法上的优化,可以大大提高代码的执行效率。

  • 算法四:
class PrimeNumberTest{
	public static void main(String[] args){
		long start = System.currentTimeMillis();
		lable:for(int i=2; i<=100000; i++){//遍历100000以内的自然数
			//优化二:对本身是质数的自然数是有效的。
			for(int j=2; j<=Math.sqrt(i); j++){//j:被i去除   
				if(i%j == 0){//i被j除尽
					continue lable;//终止指定标签的for循环的本次循环操作
				}
			}
			//凡是能执行到这个步骤的,一定是质数,因为非质数全都被终止当次的循环操作了
			System.out.println(i);
		}
		long end = System.currentTimeMillis();
		System.out.println("程序执行时间:" + (end - start));
	}
}

进一步对算法三进行了代码优化,省去了结果状态标识的定义,使用continue关键字并指定for循环标签,终止指定标签的for循环的当次操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值