本文所用解释器为python2.7
1 求素数方法的优化
(1)filter()的使用
filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。
filter(function, iterable)
function – 函数名(返回值必须是逻辑值),iterable – 可迭代对象。
def is_odd(n):
return n % 2 == 1
tmplist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
newlist = list(tmplist)
print(newlist)
输出
[1, 3, 5, 7, 9]
从结果可以看到,filter的用法,就是将[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]中的元素,一个一个地代入到函数is_odd中,如果代进去为True,那么就保留,否则过滤掉,返回一个迭代器对象。
filter()的第一个参数,也可以为匿名函数
import math
tmplist = filter(lambda x:math.sqrt(x) % 1 == 0, range(1, 101))
newlist = list(tmplist)
print(newlist)
输出
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
(2)五种求素数方法的对比
先看方法三,便于理解
#!/usr/bin/python
# -*- coding:utf-8 -*-
import numpy as np
import math
from time import time
# 调用time模块来实现计时
def is_prime(x):
return 0 not in [x % i for i in range(2, int(math.sqrt(x)) + 1)]
def is_prime3(x):
flag = True
for p in p_list2:
if p > math.sqrt(x):
break
if x % p == 0:
flag = False
break
if flag:
p_list2.append(x)
return flag
if __name__ == "__main__":
a = 2
b = 100000
# 方法1:直接计算
t = time()
p = [p for p in range(a, b) if 0 not in [p % d for d in range(2, int(math.sqrt(p)) + 1)]]
print time() - t
print p
# 方法2:利用filter
t = time()
p = filter(is_prime, range(a, b))
print time() - t
print p
# 方法3:利用filter和lambda
t = time()
is_prime2 = (lambda x: 0 not in [x % i for i in range(2, int(math.sqrt(x)) + 1)])
# [x % i for i in range(2, int(math.sqrt(x)) + 1)]表示x除以i得到的余数,i=2~sqrt(x)
# 因为range是左闭右开,为了保证int(math.sqrt(x))能取到,因此需要加1
# 如果x是素数,即除了1和本身以外没有其他约数,那么它除以2~sqrt(x)中的任何一个数,余数都不可能为0
# 如果0不在[x % i for i in range(2, int(math.sqrt(x)) + 1)],
# 说明x除以2~sqrt(x)中的任何一个数都除不尽,即x为素数
p = filter(is_prime2, range(a, b))
print time() - t
print p
# 方法4:定义
t = time()
p_list = []
for i in range(2, b):
flag = True
for p in p_list:
if p > math.sqrt(i):
break
if i % p == 0:
flag = False
break
if flag:
p_list.append(i)
print time() - t
print p_list
# 方法5:定义和filter
p_list2 = []
t = time()
filter(is_prime3, range(2, b))
print time() - t
print p_list2
print '---------------------'
a = 1180
b = 1230
a = 1600
b = 1700
p_list2 = []
p = np.array(filter(is_prime3, range(2, b+1)))
p = p[p >= a]
print p
p_rate = float(len(p)) / float(b-a+1)
print '素数的概率:', p_rate, '\t',
print '公正赔率:', 1/p_rate
print '合数的概率:', 1-p_rate, '\t',
print '公正赔率:', 1 / (1-p_rate)
输出
方法一耗时3.58秒,方法二1.92,方法三1.97,方法四0.36,方法五0.28
方法一使用列表生成器;方法二是将列表生成器转化判断函数,再套上了一filter方法,耗时明显比第一种方法耗时短;方法三是将方法二中的函数改成了匿名函数,消耗的时间与方法二相当;方法四直接按照定义去求,完全舍弃了列表生成器,用时大大缩短;方法五是对方法四进行了改进,套上了一层filter。
可以看到,使用filter能在一定程度上优化算法,但是优化的程度,远没有算法的改进效果好。
2 环形公路堵车模型
本节参考自博客:https://blog.csdn.net/weixin_42567027/article/details/107398651
(1)模型假设
路面上有n辆车,以不同的速度向前行驶, 模拟堵车问题。
有以下假设:
假设道路为环形封闭,即路面上的车不会少,也不会多,外面的车进不来,里面的也出不去。
某辆车的当前速度是v。
若前方可见范围内没车(即d>v),则它在下一秒的车速提高到v+1,直到达到规定的最高限速。
若前方有车,前车的距离为d,若d < v,则它下一秒的车速降低到d-1 ,若d=v,则速度不变。
每辆车会以概率p随机减速v-1。
#!usr/bin/env python
# -*- coding:utf-8 -*-
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
# 对车辆的位移进行限制,当大于水平的公路长度时,则认为是该车进入了下一圈
def clip(x, path):
for i in range(len(x)):
if x[i] >= path:
x[i] %= path
if __name__ == "__main__":
# 文字转化
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
'''初始化定义'''
path = 5000 # 环形公路的长度
n = 100 # 公路中的车辆数目
v0 = 50 # 车辆的初始速度
p = 0.3 # 随机减速概率
Times = 1000 # 模拟时间
'''模拟车辆的位移和速度'''
np.random.seed(0)
# 模拟100辆车辆的位置
# np.random.rand(n)返回的是n个0-1之间均匀分布的随机数
x = np.random.rand(n) * path
# 根据车辆的位置进行排序,原地替换
x.sort()
# 将所有车辆的初速度定义为50,并设为float类型数据
v = np.tile([v0], n).astype(np.float)
'''画布大小'''
plt.figure(figsize=(8, 6))
'''模拟在时间范围内的堵车情况'''
for t in range(Times):
# 根据第t时刻每辆车的位置绘图
# x:车辆位置 [t]*n:时间,因为要保持横纵坐标的长度要相同
plt.scatter(x, [t] * n, s=1, c='b', alpha=0.05) # alpha表示点的透明度
'''计算每辆车第t时刻的速度和第t+1时刻的位置'''
for i in range(n):
# 计算前后车辆的距离
# 对于最后一辆车,即 x[n-1],它的前一辆车是 x[n]
# 但 x[n]会发生索引越界,因此使用 x[(i + 1) % n]代替 x[i+1]
if x[(i + 1) % n] > x[i]:
# 判断x[(i + 1) % n] > x[i],是为了判断前面的车是否已经进入下一圈
# 因为假定没有超车的情况发生,因此前面的车,永远在前面
d = x[(i + 1) % n] - x[i]
else:
d = x[(i + 1) % n] + path - x[i]
'''根据与前车的距离调整速度'''
if v[i] < d:
# v[i] < d 表示前方可见范围没车
# 若前方可见范围内没车,则它在下一秒的车速提高到v+1,直到达到规定的最高限速。
# 同时,每辆车会以概率p随机减速v-1。
if np.random.rand() > p:
v[i] += 1
else:
v[i] -= 1
elif v[i] > d:
# 若前方有车,前车的距离为d,且d < v,则它下一秒的车速降低到d-1 。
v[i] = d - 1
# 还有一种情况,若v[i] = d,则第 i 辆车的速度不做调整
# 限制速度,v<0,则将v定义为0;v>150,则将v定义为150
v = v.clip(0, 150)
# 车辆的位移在增加,车在往前开
x += v
# 调用clip,因为公路是环形封闭的,有些车已经进入下一圈了
clip(x, path)
'''限制坐标轴'''
# 对x轴的坐标进行限制
plt.xlim(0, path)
# 对y轴坐标进行限制
plt.ylim(0, Times)
'''标签'''
# 后面字符串以 Unicode 格式进行编码,一般用在中文字符串前面,
# 防止因为源码储存格式问题,导致再次使用时出现乱码。
# Python2.7需要在中文字符串前面加u,否则报错,Python3.X不需要
plt.xlabel(u'车辆位置', fontsize=16) # fontsize表示字体大小
plt.ylabel(u'模拟时间', fontsize=16)
plt.title(u'环形公路车辆堵车模拟', fontsize=20)
'''自动调整子图参数,使之填充整个图像区域'''
plt.tight_layout(pad=2)
'''画图'''
plt.show()
输出
如图所示,若以 p = 0.3 的概率减速,则会发生堵车,蓝色点密集的地方表示堵车
若以 p=0.15,则
可以看到,堵车仅仅发生最初时刻,后面的图像变得均匀,说明没有再发生堵车。