质数也就是大于1的整数中,除了1和它本身以外不能被其他整数整除的数,也叫素数。
问题:现给定一个任意整型参数 N(N>1),求出小于N 的质数的个数。这里主要介绍五种算法,前三种思路一致,主要是效率的差异;第五种采用了埃拉托斯特尼筛法进行计算。
例如: 输入 10,输出:4(2,3,5,7); 输入:20, 输出: 8(2,3,5,7,11,13,17,19);
第一种算法:
针对小于N的每个正整数x,我们可以遍历从2到x-1遍历去试除,当出现一个数能被整除,那这个数就不是质数;当然这种方法也是最容易想到的方法,但效率也是最低的方法;
代码如下:
class Calculator(object):
def prime(self, n):
m = 0
for i in range(2, n):
j = 2
for j in range(2, i-1):
if i % j == 0:
break
else:
m += 1
return m
第二种算法:
我们可以遍历从2到x/2的数去试除,这样子相对于第一种方法节省了近一半的时间;
代码如下:
class Calculator(object):
def prime(self, n):
m = 0
for i in range(2, n):
j = 2
for j in range(2, int(i/2)+1):
if i % j == 0:
break
else:
m += 1
return m
第三种算法:
我们可以针对第二种算法进一步优化,遍历从2到√x;
因为数学的因数都是成对出现的,如果出现一个大于√x的因数,必然有一个小于√x的因数存在,因此我们遍历到√x就可以判定一个数是不是质数;例如:16, 1*16, 2*8, 4*4;
代码如下:
class Calculator(object):
def prime(self, n):
m = 0
for i in range(2, n):
j = 2
for j in range(2, int(i**0.5)+1):
if i % j == 0:
break
else:
m += 1
return m
第四种算法:
对于任意一个大于3的合数(除了1和自身外,还能被其他整数整除的数),我们都可以将其拆分成至少包含一个质数的因子相乘;例如:20=2*10(2是质数);45=5*9;利用此点,我们可以采用遍历小于这个数的所有质数来确认这个数是不是质数。
代码如下:
class Calculator(object):
def prime(self, n):
if n <= 2:
return 0
else:
prime_list = list()
prime_list.append(2) # 先将2加入到要遍历的列表中
for x in range(3, n):
y = False
for y in prime_list:
if x % y == 0: # 对小于n的x进行遍历,当某个数整除为0时,不执行添加列表操作
y = False
break
else:
y = True
if y is True:
prime_list.append(x) # 对小于x的质数进行遍历后,没有能整除的质数,则这个数也是质数
return len(prime_list)
第五种算法:
埃拉托斯特尼筛法;使用的原理是从2开始,将每个素数的各个倍数,标记成合数。一个素数的各个倍数,是一个差为此素数本身的等差数列。此为这个筛法和试除法不同的关键之处,后者是以素数来测试每个待测数能否被整除。(摘自维基百科)
具体的实现方式:
先留下第一个素数2,将所有2的倍数的合数全部剔除;下一个素数3,将3的倍数的所有合数全部剔除;接着用5进行筛选剔除;当所要使用的素数的平方大于设定值时,停止筛选,则剩下的所有数均为素数。
例如:求出小于120的所有素数,依次使用2,3,5,7进行筛选,当到11时,11*11>120,停止筛选,剩余数即为质数。
class Calculator(object):
def prime(self, n):
if n <= 2:
return 0
is_right = [True] * n
is_right[1] = False
for i in range(2, int(n ** 0.5) + 1):
if is_right[i]:
for j in range(i * i, n, i):
is_right[j] = False
m = 0
for x in range(2, n):
if is_right[x]:
m += 1
return m