python学习——练习题(12)
""" 题目:判断101-200之间有多少个素数,并输出所有素数。 质数(prime number)又称素数,有无限个。 质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数。 """ import math def answer1(): """ 根据素数定义,一个一个判断 :return: """ print("输出一", end=":") sumCount = 0 findTimes = 0 for i in range(101, 2000): for j in range(2, i): findTimes += 1 if i % j == 0: break else: print(i, end=",") sumCount += 1 print("共%d个" % sumCount, end=",") print("共比较了%d次" % findTimes) answer1() def answer2(): """ 上述判断方法,明显存在效率极低的问题。对于每个数n,其实并不需要从2判断到n-1,我们知道,一个数若可以进行因数分解, 那么分解时得到的两个数一定是一个小于等于sqrt(n),一个大于等于sqrt(n),据此,上述代码中并不需要遍历到n-1,遍历到sqrt(n)即可, 因为若sqrt(n)左侧找不到约数,那么右侧也一定找不到约数。 :return: """ print("输出二", end=":") sumCount = 0 findTimes = 0 for i in range(101, 2000): sqrtNum = int(math.sqrt(i)) for j in range(2, sqrtNum + 1): findTimes += 1 if i % j == 0: break else: print(i, end=",") sumCount += 1 print("共%d个" % sumCount, end=",") print("共比较了%d次" % findTimes) answer2() def answer3(): """ 方法(2)应该是最常见的判断算法了,时间复杂度O(sqrt(n)),速度上比方法(1)的O(n)快得多。最近在网上偶然看到另一种更高效的方法,暂且称为方法(3)吧, 由于找不到原始的出处,这里就不贴出链接了,如果有原创者看到,烦请联系我,必定补上版权引用。下面讲一下这种更快速的判断方法; 首先看一个关于质数分布的规律:大于等于5的质数一定和6的倍数相邻。例如5和7,11和13,17和19等等; 证明:令x≥1,将大于等于5的自然数表示如下: ······ 6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1 ······ 可以看到,不在6的倍数两侧,即6x两侧的数为6x+2,6x+3,6x+4,由于2(3x+1),3(2x+1),2(3x+2),所以它们一定不是素数,再除去6x本身, 显然,素数要出现只可能出现在6x的相邻两侧。这里有个题外话,关于孪生素数,有兴趣的道友可以再另行了解一下,由于与我们主题无关,暂且跳过。 这里要注意的一点是,在6的倍数相邻两侧并不是一定就是质数。 根据以上规律,判断质数可以6个为单元快进,即将方法(2)循环中i++步长加大为6,加快判断速度,代码如下: 高手无处不在啊 由上可得,只要从96开始,每6个计算一次 :return: """ print("输出三", end=":") sumCount = 0 findTimes = 0 for i in range(102, 2000, 6): for num in (i - 1, i + 1): sqrtNum = int(math.sqrt(num)) for j in range(2, sqrtNum + 1): findTimes += 1 if num % j == 0: break else: print(num, end=",") sumCount += 1 print("共%d个" % sumCount, end=",") print("共比较了%d次" % findTimes) answer3() def answer4(): """ 上面的方法,高手还可以改进 因为上述可得,6x-1和6x+1坑定不会被6x,6x+2,6x+3,6x+4整除,弱它是素数,那么它也是被6x-1或6x+1整除 所以上面方法,里面的判断也可以跨6来判断 :return: """ print("输出四", end=":") sumCount = 0 findTimes = 0 for i in range(102, 2000, 6): for num in (i - 1, i + 1): sqrtNum = int(math.sqrt(num)) for j in range(5, sqrtNum + 1, 6): findTimes += 1 if num % j == 0 or num % (j + 2) == 0: break else: print(num, end=",") sumCount += 1 print("共%d个" % sumCount, end=",") print("共比较了%d次" % findTimes) answer4() def answer5(): """ 排除偶数,数组统计 :return: """ print("输出五", end=":") findTimes = 0 numList = [] for i in range(101, 2000, 2): numList.append(str(i)) sqrtNum = int(math.sqrt(i)) for j in range(2, sqrtNum + 1): findTimes += 1 if i % j == 0: numList.pop() break print(",".join(numList), end=",") print("共%d个" % len(numList), end=",") print("共比较了%d次" % findTimes) answer5() class answer6: """ 练习迭代器 """ def __init__(self): """ 构造函数 """ self.sumCount = 0 self.findTimes = 0 self.startNum = 102 self.endNum = 2000 print("输出六", end=":") def __iter__(self): """ 迭代器 :return: """ return self def __next__(self): """ 迭代器next :return: """ if self.startNum > self.endNum: raise StopIteration for num in (self.startNum - 1, self.startNum + 1): sqrtNum = int(math.sqrt(num)) for i in range(5, sqrtNum + 1, 6): self.findTimes += 1 if num % i == 0 or num % (i + 2) == 0: break else: print(num, end=",") self.sumCount += 1 self.startNum += 6 answer = answer6() for i in answer: pass print("共%d个" % answer.sumCount, end=",") print("共比较了%d次" % answer.findTimes) def answer7(): """ 练习yield生成器,注意和answer6区域 """ print("输出七", end=":") startNum = 102 sumCount = 0 findTimes = 0 while startNum < 2000: for num in (startNum - 1, startNum + 1): sqrtNum = int(math.sqrt(num)) for i in range(5, sqrtNum + 1, 6): findTimes += 1 if num % i == 0 or num % (i + 2) == 0: break else: sumCount += 1 print(num, end=",") yield num startNum += 6 print("共%d个" % sumCount, end=",") print("共比较了%d次" % findTimes) for i in answer7(): pass def answer8(): """ 练习数组生成器表达式 参考:http://blog.csdn.net/u014745194/article/details/70176117 :return: """ print("输出八", end=":") numList = list(filter(lambda x: x not in set([i for i in range(101, 200) for j in range(2, i - 1) if not i % j]), range(101, 200))) print(numList, end=",") print("共%d个" % len(numList)) answer8()