质数识别/列举算法

首先了解概念:质数,也被称为素数,是指除了1跟它本身没有其他因数的数。1既不是质数也不是合数,2是最小的质数。

问题:列举小于任意数Num的质数

可以把这样一个问题分解为两个功能模块,List_Prime(Num)和is_Prime(n),其中is_Prime(n)嵌套在List_Prime(Num)中。

算法1:首先从2开始迭代累加到num,该部分是List_Prime(Num)。对于任意一个数n,需要判断它是不是质数,即is_Prime(n)。对2到n-1取余(取模),如果发现有余数为0的情况,则说明有因数存在,n不是质数。否则,n是质数。

我们发现,所有质数都是奇数,所以在从2迭代到num的过程中,每次累加2而不是1。

算法2: List_Prime(Num)进行改进,从2迭代到num的过程中每次增加2,这样每次只判断奇数是不是质数,is_Prime(n)与算法1思路相同。可以提高50%的效率。

我们也发现,任何一个合数都是由质因子组成的,比如10=2*5,12=2*2*3。所以在算法2的基础上,我们可以改进is_Prime(n)。

算法3:List_Prime(Num)与算法2相同。对于is_Prime(n),我们不需要考察从2到n-1的所有的数,只需要考察之前得到的质数即可。比如对于7,我们只需要看2,3,5是不是7的因子,而不需要看2,3,4,5,6。可以在算法2的基础上提高约50%的效率。

对于任何一个数num,一定需要考察所有比num小的质数是不是其因子吗?比如对于7,需要考察7能不能被2、3、5整除么?其实不需要,因为任何一个合数都至少可以分解成两个数,而其中一个必然可以是质数。(任何一个合数都可以转化为若干质数相乘的形式)所以对于num,在所有小于它的质数中,我们只需要判断“前一半”(严格说是前一部分)是不是num的因子即可,因为另外的“后一半”要依靠前一半存在。

比如对于11,我们判断2、3都不是其因子,5和5以后就不需要了,因为若因子有5,一定存在另一个大于5的因子y使得5*y=11,但11比25都小,所以更不可能有5*y=11了。所以我们可以用质数的平方来作判断条件,如果比当前质因子平方大或相等就继续判断,如果小则返回true。比如对于num=11

2*2<num, 考察2是不是num的因子,不是,继续;

3*3<num, 考察3是不是num的因子,不是,继续;

5*5>num, 返回true,num是质数。因为不可能有5和5以后的质数作为num的因子了,若有则必有小于5的质数作为num的另一个因子,但之前判断它们都不是。

算法4:List_Prime(Num)与算法3相同。对于is_Prime(n),我们不需要考察之前得到的所有质数即可,只考察平方小于等于n的质数是不是其因子。

Ruby的代码如下

$arr=[]

$arr[0]=2

def add_prime(n)

    3.step(n,2){|num|$arr<<numifis_prime?num}

end

 

def is_prime?(number)

   j=0

  while $arr[j]*$arr[j]<=number

      return falseifnumber%$arr[j]==0

      j+=1

  end

  return true

end

 

add_prime(50)

print $arr.join(","),"\n"

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值