Python学习之---求100以内素数的八种解法

题目: 求100以内所有的素数和个数

延伸:任意范围内的素数和前N个素数的和.

定义

何为素数?素数(又称为质数)就是在所有比1大的整数中,除了1和它本身以外,不再有别的因数,这种整数叫做质数。还可以说成质数只有1和它本身两个约数。2.素数是这样的整数,它除了能表示为它自己和1的乘积以外,不能表示为任 何其它两个整数的乘积。

解法

知道了素数的定义之后,该如何求解素数呢?不论是求和,还是求解任意范围内的素数,其基本原理都是一样,都需要求解出特定范围内的素数,剩下的只是取值界限不一样而已,因此,在这里我们用100以内的素数为例,讲解下在python中如何求解.

方法一: 穷举法

n=100
count =0
primenumber=[]
for x in range (2,n+1):
    for i in range(2,x):
        if x%i ==0:
            break
    else:
        count+=1
        primenumber.append(x)
print(count)
print(primenumber)

方法二: 开方减"半"法

#解释:一个非质数的整数一定能拆分成两个数的乘积(废话么),重点在这两个数(还是废话)一定有一个数小于等于其开方值.
#举例:36 可以拆分成2*18   3*12  6*6   1* 36  也就是说能被拆分的数两个数一定有一个数是在[1,6]之间,如果
#在[1,6]之间都找不到一个数可以被36整除,那么6以后的数也一定不会存在.
#下面就可以缩小循环的下限值了:
n=100
count =0
primenumber=[]
for x in range (2,n+1):
    for i in range(2,int(pow(x,0.5))+1):
        if x%i ==0:
            break
    else:
        count+=1
        primenumber.append(x)
print(count)
print(primenumber)

方法三:去除偶数法

#解释:在方法2的基础上已经剔除了很多无用的数,但是其中还是有很多数是没有必要算的,比如所有的偶数,(2除外.为什么呢?因为2是特殊的质数)
#所有的偶数都可以被2整除,也就一定不是素数.
#把上面的代码优化一下:
n=100
count =1
primenumber=[2]#2为特殊,所以需要额外加上质数2
for x in range (3,n+1,2):  #要去除所有偶数,那么可以重3开始循环
    for i in range(3,int(pow(x,0.5))+1):#取进来的数都是奇数了,那么和2除就没有意义,故这里也重3开始
        if x%i ==0:
            break
    else:
        count+=1
        primenumber.append(x)
print(count)
print(primenumber)

方法四:使用列表法


#解释:根据方法三,去除了偶数,也"减半"了,但奇数中还有很多不是素数,例如15,25,30等能被5整除,9,18,27等能被3整除,
#因此可以进一步优化代码.
#去除以上数,可以在循环前用if 语句进行预先判断一下,如果满足条件就不进行循环,这样也可以减少部分运算量,尤其当所求
#素数非常大时,能提高不少效率,由于较为简单,不在介绍,下面主要介绍另外一种方法.

#质数列表: 讲所求的质数作为一个质数列表,合数一定可以分解为几个质数的乘积  

n=100
count = 1
primenumber=[2]
for x in range(3,n+1,2):
    for  i  in primenumber:
        if x%i==0:
            break
    else:
        primenumber.append(x)
        count += 1
print(count)
print(primenumber)  

#优化算法: 列表内数据开方"减半"

n=100
count = 1
primenumber=[2]
for x in range(3,n+1,2):
    flag =False
    edge =int(pow(x,0.5))
    for  i  in primenumber:
        if i > edge:
#   for  i  in primenumber:      #比较注释行与上面三行代码,哪种代码的运算效率更高?为什么
#       if i> int(pow(x,0.5)):
            flag = True
            break
        if x%i==0:
            flag=False
            break
    if flag:
        primenumber.append(x)
        count += 1
print(count)
print(primenumber)  

方法五:素数性质法

#解释---所有大于三的素数只有6N-1,和6N+1两种形式(证明略)  

n=100
count=3 #  初始值2,3,5
x=7
step =4
primenumber=[2,3,5]
while x< n:
    if x%5!=0:
        edge=int(x**0.5)+1
        for i in range(3,edge,2):
            if x %i ==0:
                break
        else:
            count+=1
            primenumber.append(x)
    x+=step
    step=4 if step==2 else 2
    
print(count)
print(primenumber)  

方法六: 埃拉托斯特尼筛法

埃拉托斯尼

#埃拉托斯特尼筛法:
#定义:要得到自然数n以内的全部素数,必须把不大于  的所有素数的倍数剔除,剩下的就是素数。 
#给出要筛数值的范围n,找出以内的素数。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个质数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个质数5筛,把5留下,把5的倍数剔除掉;不断重复下去......。
h  = [True] * 100#开辟内存空间
h[:2] = [False, False]#排除特殊的0和1
for i in range(2, int(100 ** 0.5) + 1):
    if h[i]:
        h[i*i::i] = [False] * len(h[i*i::i])

s=''
for i, e in enumerate(h):
    if e:
        s += str(i) + ' '
print(s.strip())
#变形后
n=1000
p=[True]*(n+1) #定义素数可能出现的区间,一次开辟所需内存
p[0]=p[1]=False
p[2]=True
count=1
for x in range(2,int(n**0.5)+1):  #定义取值范围
    if not p[x]:#排除已经是乘积因子求出的数
        continues
    for i in range(x*x,n+1,x):#标记是乘积因子的数,如2*2  2*3  2*4.........3*3  3*4   发现全部排除
        p[i]=False    
primes=[i for i in range(n+1)if p[i]]#取出上面集合中没有被排除的数,因为已经计算所有乘积的结果,
#所有剩下的数,一定没有乘积,即为素数
print(primes)

总结

求解素数基本原理就是一个遍历循环的过程,如何在循环中去除不必要的数,降低循环次数,降低时间复杂度,是判断求解素数方法好坏的重要标准之一.

最后,奉上两个大牛写的代码,用于瞻仰,吾等学习之榜样:

#立个flag,等哪天我也能随便写出这样的代码.就来把这个赞美删掉!欢迎监督
#法一:
print (list(p for p in range(2, 100) if 0 not in ( p%i for i in range(2,int(pow(p,0.5))+1))))
#法二:
print(" ".join("%s" % x for x in range(2,100) if not [y for y in range(2,x) if x % y ==0]))

果然python什么都能用一行代码解决。。。

猜你喜欢

转载自blog.csdn.net/qq_40498551/article/details/89023183
今日推荐