Eratosthenes的Python筛不起作用

Eratosthenes的Python筛不起作用,python,sieve-of-eratosthenes,sieve,Python,Sieve Of Eratosthenes,Sieve,首先,这是我的家庭作业,我目前正在python上筛选Eratosthenes。 我的程序看起来像: x=[] for i in range(2,100): x.append(i) primes=[] i=2 while len(x)!=0: k=x[0] x.pop(0) primes.append(k) while k*i in x: x.remove(k*i) i+=1 print(primes) p

首先,这是我的家庭作业,我目前正在python上筛选Eratosthenes。 我的程序看起来像:

x=[]
    for i in range(2,100):
        x.append(i)
primes=[]
i=2

while len(x)!=0:
    k=x[0]
    x.pop(0)
    primes.append(k)
    while k*i in x:
        x.remove(k*i)
        i+=1

print(primes)
print(x)
当我的程序打印“素数”时,我得到:

[2, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39,
41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77,
79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99]
为什么列表中有复合数字?看来这个计划应该能奏效

# 编辑了程序,现在看起来:

x=[]
for i in range(2,100):
    x.append(i)
primes=[]



while len(x)!=0:
    i=2
    k=x[0]
    x.pop(0)
    primes.append(k)
    while k*i<=max(x):
        x.remove(k*i)
        i+=1
        if k*i not in x:
            i+=1

print('primes','\n',primes,sep='')
print('x','\n',x,sep='')
x=[]
对于范围(2100)内的i:
x、 附加(i)
素数=[]
而len(x)=0:
i=2
k=x[0]
x、 流行音乐(0)
素数追加(k)

当k*i时,一个问题是您只会添加到
i
。每次从列表中弹出另一个元素时,需要将
i
重置回2

也就是说,首先从列表中弹出2。逐渐增加
i
以从列表中删除2的所有倍数。在此结束时,
i
将为50。但是当你返回并从列表中弹出3时,
i
仍然是50,所以它只在列表中查找
50*3


即使你修复了这个问题,它仍然无法工作,因为一旦你找到一个不在列表中的值,你就会停止查看
i
值。但是有可能
k*i
不在列表中,但是
k*(i+1)
是——例如,当你把2的倍数乘以后,3的第一个倍数(即6)不在列表中,但下一个倍数(即9)在列表中。因此,除非您尝试列表最大值的每一个倍数,否则您无法停止。一个问题是您只能将其添加到
i
。每次从列表中弹出另一个元素时,需要将
i
重置回2

也就是说,首先从列表中弹出2。逐渐增加
i
以从列表中删除2的所有倍数。在此结束时,
i
将为50。但是当你返回并从列表中弹出3时,
i
仍然是50,所以它只在列表中查找
50*3

即使你修复了这个问题,它仍然无法工作,因为一旦你找到一个不在列表中的值,你就会停止查看
i
值。但是有可能
k*i
不在列表中,但是
k*(i+1)
是——例如,当你把2的倍数乘以后,3的第一个倍数(即6)不在列表中,但下一个倍数(即9)在列表中。因此,在尝试列表最大值之前,您不能停止。注释:

  • 应该使用更具描述性的变量名
  • 每次进入k*i in x循环时,需要在2处重新启动i
  • x、 对于大x,pop(0)速度较慢
  • x、 对于大x,移除(k*i)速度较慢
  • 应将内部while循环更改为“whilek*i
下面是一个使用位列表的工作快速筛选: 评论:

  • 应该使用更具描述性的变量名
  • 每次进入k*i in x循环时,需要在2处重新启动i
  • x、 对于大x,pop(0)速度较慢
  • x、 对于大x,移除(k*i)速度较慢
  • 应将内部while循环更改为“whilek*i
下面是一个使用位列表的工作快速筛选:
你应该接受@BrenBarn的答案,因为它涵盖了重要的内容。但这里还有一些提示:

  • 有一种更简单、更快的方法来创建初始
    x
    列表
让Python为您做这件事。只需将
range()
包装在
list()
中,如下所示:

MAX_NUM = 100
x = list(range(2, MAX_NUM))
以后我们将有更多机会使用
MAX_NUM
;继续读下去

  • 在Python中,最好使用
    for
    循环和
    range()
    而不是
    ,同时将
    循环添加到索引变量中
而不是:

i = 2
while k*i <= max(x):
    # do stuff with k*i
    i += 1
Python内置的
range()
将为您生成一系列值,从
k*2
开始,每次添加
k
,并以
k
的最后倍数(小于
max(x)
停止。现在,您的循环运行得更快,并且避免了一系列倍增

  • 与索引
    x[0]
    以获取
    k
    ,然后使用
    x.pop()
    放弃
    x
    中的
    k
    值不同,有一种更简单的方法
list.pop()
返回弹出的值。所以你可以在一行中这样做:

k = x.pop()
  • 您多次计算
    max(x)
    。但是您已经知道
    x
    中的最大数字,因为您构建了
    x
    。在构建
    x
    时,您可以在变量中保存最大值,并使用此变量,而不是反复查找
    max(x)
    max(x)
    的好处在于它不会检查已取出的数字;例如,当
    k
    为3时,99将被删除。但是
    max(x)
    非常昂贵,所以我认为仅仅使用保存的值是一个整体的胜利
这就是为什么我保存了
MAX\u NUM
。所以你可以这样做:

for i in range(k*2, MAX_NUM, k):
    # do stuff with i
for k in range(2, MAX_NUM):
    if k not in x:
        continue
  • 如果您刚刚开始,您可能不知道Python的
    set()
    类,但它对解决这个问题有好处。正如dstromberg在其回答中所说,
    x.remove(some_value)
    x
    包含许多值时速度较慢。但是从
    集合中删除值总是一个非常快速的操作
您可以像这样构建一个集合:

x = set(range(2, 100))
此集合将包含2到99(含)之间的所有整数值

然后,关于集合的一个巧妙之处是:使用
.discard()
成员函数(使用
集合
的另一件便宜的事情),您可以在不检查成员是否在集合中的情况下除去成员

实际上,
中的
(用于列表)和
list.remove()
都很昂贵。因此,一个
集合
将两个昂贵的操作替换为一个便宜的操作

一旦您的原始程序进入工作状态,请保留它的副本,然后将其重写为使用
集合
而不是
列表
。将最大整数从
# list solution
if i in my_list:
    my_list.remove(i)

# set solution
my_set.discard(i)
for k in range(2, MAX_NUM):
    if k not in x:
        continue
result = list(my_set)  # get a list of values stored in my_set
print('primes','\n',primes,sep='')
print('primes')
print(primes)
print('primes:\n{}'.format(primes))