前言
先前针对“在一平面直角坐标系上小云兮在遛狗狗,一开始的运动方向为x轴正方向。现记其走过的路程为s,当s为素数时,遛狗的前进方向顺时针旋转90度。现问当总路程x等于某一输入值时,其在x轴或y轴方向上所达到的最遥远两端的距离”这一问题粗浅地写了素数转圈问题1.0来解决。但经过实际测试发现,在总路程x越来越大,例如令x=100000(十万)时,时间戳的计算结果已经达到了60.54499888420105s,已经在一定程度上失去了其实用性,故本文素数转圈问题1.1主要着手优化该程序在面对较大数据的处理速度问题。
问题分析
经过对原代码的逐一分析,可以得到原代码在“第一步:收集x以内的素数”模块上直截粗暴,采用的是将所有小于输入值的正整数逐个除输入值,通过舍去能被整除的数来判断的,此过程会占用大量内存,低效缓慢:
#原代码
def is_prime(num,list):
#判断素数并收集到list
if num==0 or num==1:
return()
for factor in range(2,num):
if num%factor==0:
return()
list.append(num)
return()
在“第二步:计算每段的长度”上代码稍有冗长,且没有必要额外定义函数:
#原代码
def delta_lists(n,list1,list2,delta_list):
#两个列表中数据逐项做差,并收集到delta_list
for factor in range(n):
m=list1[factor]-list2[factor]
delta_list.append(m)
return()
接下来就是要先解决这些核心问题。
优化一:收集x以内的素数
这里采用除去特例的情况下,优先排除被2,3整除的数据,在通过分析因子,并提前跳过3的倍数,来化简运算,代码如下:
def is_prime(n,list):
if n<=1: # 0和1不是质数
return ()
elif n==2 or n==3: # 2和3是特例,它们是质数
list.append(n)
elif n%2==0 or n%3==0: # 质数一定不能被2或3整除
return ()
i=5
while i*i<=n: # 验证到i^2是否大于n即可,因为后续的因子都是6k±1的形式
if n%i==0 or n%(i+2)==0:
return ()
i+=6 # 提前跳过3的倍数
list.append(n)
return ()
优化二:计算每段的长度
摒弃定义函数的冗余做法,选择在列表中运算,并直接放到主体部分去,代码如下:
delta_list=[a-b for a,b in zip(list1, list2)]
也顺带将变量赋值写的方便看一些,代码如下:
#原代码
x=0
y=0
xmax=0
xmin=0
ymax=0
ymin=0
#现在
x,y,xmax,xmin,ymax,ymin=0,0,0,0,0,0
全部代码
素数转圈问题1.1全部代码如下:
def is_prime(n,list):
if n<=1: # 0和1不是质数
return ()
elif n==2 or n==3: # 2和3是特例,它们是质数
list.append(n)
elif n%2==0 or n%3==0: # 质数一定不能被2或3整除
return ()
i=5
while i*i<=n: # 验证到i^2是否大于n即可,因为后续的因子都是6k±1的形式
if n%i==0 or n%(i+2)==0:
return ()
i+=6 # 提前跳过3的倍数
list.append(n)
return ()
def extreme_value(max,min,x):
#极值
if x>=max:
max=x
if x<=min:
min=x
return(max,min)
def divide_xy_ans(n,delta_list):
#区分x,y方向位移并计算
x,y,xmax,xmin,ymax,ymin=0,0,0,0,0,0
for factor in range(n):
if factor%4==0:
x+=delta_list[factor]
xmax,xmin=extreme_value(xmax,xmin,x)
continue
elif factor%4==1:
y-=delta_list[factor]
ymax,ymin=extreme_value(ymax,ymin,y)
continue
elif factor%4==2:
x-=delta_list[factor]
xmax,xmin=extreme_value(xmax,xmin,x)
continue
elif factor%4==3:
y+=delta_list[factor]
ymax,ymin=extreme_value(ymax,ymin,y)
xans=xmax-xmin
yans=ymax-ymin
return(xans,yans)
#主体部分
print('问题:在一平面直角坐标系上小云兮在遛狗狗,一开始的运动方向为x轴正方向。\
现记其走过的路程为s,当s为素数时,遛狗的前进方向顺时针旋转90度。\
现问当总路程x等于某一输入值时,其在x轴或y轴方向上所达到的最遥远两端的距离。')
list1=[]
delta_list=[]
num=int(input("请输入移动总路程:"))
if num==0 or num==1 or num==2:
xans=num
yans=0
else:
for factor in range(num):
is_prime(factor,list1)
list2=list1.copy()
list2.insert(0,0)
n=len(list1)
delta_list=[a-b for a,b in zip(list1, list2)]
if num not in list1:
delta_list.append(num-list1[n-1])
n_final=len(delta_list)
xans,yans=divide_xy_ans(n_final,delta_list)
ans=max(xans,yans)
print('水平方向的极差=',xans,'竖直方向的极差=',yans,'最大的极差=',ans)
测试优化结果
程序在优化之后效率有了显著提升,对于同样的令x=100000(十万),素数转圈问题1.1的时间戳计算结果为0.14970755577087402s,而对于更大数量级的x=1000000(一百万),时间戳的计算结果为3.7286486625671387s,比素数转圈问题1.0快了许多。
小结
这一次优化了程序的运算效率问题,有明显的效果。但在代码的其他方面仍有可优化之处,期待下次优化。