【问题标题】:Sieve of eratosthenes using dictionaries in python在python中使用字典筛选eratosthenes
【发布时间】:2015-04-07 05:01:04
【问题描述】:

以下是埃拉托色尼筛的两种形式。


1) 第一个是我在观看这个可汗学院视频 (https://www.khanacademy.org/computing/computer-science/cryptography/comp-number-theory/v/sieve-of-eratosthenes-prime-adventure-part-4) 时解释如何对 Sieve 进行编程的方式,该算法使用模块化除法。


2) 第二个是我为加速算法所做的一些修改,包括:使用字典并从字典中删除复合元素使用乘法查找复合元素而不是模除法来测试它们,然后在之后创建一个排序列表筛子完成了。

第二种方法要快得多,但我必须添加一条 try 语句以避免函数尝试删除已删除的值,但仍删除先前数字的倍数的元素,但仍会删除未删除的元素尚未删除。

问题是,有没有办法避免已经发现是复合的值,而不是使用 try 语句跳过它们,同时仍然使用乘法来定位复合?

   def Sieve_2_b(b):
      seq_primes=list()
      c=0
      for i in range(2,(1+b)):
          seq_primes.append(i)
      while (seq_primes[c]**2)<b:
          k=c
          while k<(len(seq_primes)):
              if seq_primes[k]>=(seq_primes[c]**2):
                  if seq_primes[k]%seq_primes[c]==0:
                      del seq_primes[k]
                      k-=1
              k+=1
          c+=1
      return seq_primes

    def Sieve_2_b_using_dict(b):
        seq_primes=list()
        sieve_dict=dict()
        c=0
        for i in range(2,(1+b)):
            seq_primes.append(i)
            sieve_dict[i]=0
        while (seq_primes[c]**2)<b:
            k=c
            while seq_primes[k]<=(b/seq_primes[c]):
                try:
                    del(sieve_dict[(seq_primes[k]*seq_primes[c])])
                except:
                    print(seq_primes[k],seq_primes[c],'stop this')
                    pass
                k+=1
            c+=1
        seq_primes=sorted(sieve_dict,key=sieve_dict.get)
        return seq_primes

【问题讨论】:

标签: python math encryption


【解决方案1】:

您的字典为每个键存储了一个无用的值 --- 它总是 0(这也使它成为sorted 的糟糕键)。请改用一组。

作为奖励,集合有一个移除元素的方法不会引发异常,而不管该元素是否存在于集合中。

这是我的第一个版本,大部分是从您的代码中复制和粘贴的:

def sieve_using_set(b):
    seq_primes=list(range(2, b + 1))
    sieve_set=set(range(2, b + 1))
    c=0
    while (seq_primes[c]**2)<b:
        k=c
        while seq_primes[k]<=(b/seq_primes[c]):
            sieve_set.discard(seq_primes[k] * seq_primes[c])
            k+=1
        c+=1
    return list(sorted(sieve_set))

它也快得多。速度不受 I/O 的影响(我在“字典”函数中注释掉了 print 语句),也不受过度删除的影响,因为 set 版本试图删除与字典版本相同的值。 set 版本有一个巨大的优势,它不需要 try-except 块来进行那些多余的删除。

我发现的下一个最大的节省是使用range,而不是不断地将ck 与一些计算进行比较。为此,我在文件顶部添加了import math

def sieve_using_set_and_ranges(b):
    seq_primes=list(range(2, b + 1))
    sieve_set=set(range(2, b + 1))
    for c in range(0, math.floor(math.sqrt(b)) + 1):
        for k in range(c, math.floor(b / seq_primes[c]) + 1):
            sieve_set.discard(seq_primes[k] * seq_primes[c])
    return list(sorted(sieve_set))

这是timeit.Timer.timeit 使用旧版 Python 3.1 运行 1000 次 1000 长筛子的结果:

Sieve using modular division:
5.98897910118
Sieve using dictionary:
5.10295796394
Sieve using set:
3.10129499435
Sieve using set and ranges:
1.69016003609

我使用了一个断言来证明集合版本产生的列表输出与您的两个函数相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多