You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为埃拉托斯特尼筛法(Sieve of Erathosthenes)实现支持增量更新与范围复用的缓存机制

如何为埃拉托斯特尼筛法(Sieve of Erathosthenes)实现支持增量更新与范围复用的缓存机制

当然可以实现!你想要的这种支持增量扩展、范围复用的缓存机制,刚好能完美适配埃拉托斯特尼筛法的特性,我来给你详细拆解实现思路和代码:

核心思路

我们需要维护一组缓存状态:

  • 已筛过的最大数值 max_cached
  • 对应筛法的布尔数组 sieve_cache(和你原代码一样,只存储奇数的标记,节省空间)
  • 已经生成的质数列表 primes_cache

每次调用sieve(n)时:

  1. 如果n小于等于max_cached:直接从缓存的质数列表中切片,返回所有小于n的质数
  2. 如果n大于max_cached:
    • 若第一次调用,直接用原筛法逻辑生成到n并初始化缓存
    • 若非第一次,增量扩展筛数组,只处理新增范围内需要标记的倍数,然后收集新增的质数更新缓存

具体实现代码

from math import sqrt

def cached_sieve():
    # 闭包内部维护缓存状态,避免全局变量污染
    max_cached = 0
    sieve_cache = []
    primes_cache = []

    def sieve(n):
        nonlocal max_cached, sieve_cache, primes_cache
        
        # 处理边界情况
        if n <= 2:
            return () if n <= 2 else (2,)
        
        # 情况1:当前n小于等于已缓存的最大值,直接从缓存切片
        if n <= max_cached:
            # 找到第一个大于等于n的质数位置,切片返回
            idx = 0
            while idx < len(primes_cache) and primes_cache[idx] < n:
                idx += 1
            return tuple(primes_cache[:idx])
        
        # 情况2:需要扩展筛子到n
        if max_cached == 0:
            # 第一次调用,初始化筛子(和原代码逻辑一致)
            sieve_cache = [True] * (n // 2)
            for i in range(3, int(sqrt(n)) + 1, 2):
                if sieve_cache[i // 2]:
                    sieve_cache[i*i//2::i] = [False] * ((n - i*i - 1) // (2*i) + 1)
            primes_cache = [2] + [2*i + 1 for i in range(1, n//2) if sieve_cache[i]]
            max_cached = n
            return tuple(primes_cache)
        else:
            # 扩展筛数组:计算需要新增的长度
            new_total_length = (n - 1) // 2
            sieve_cache.extend([True] * (new_total_length - len(sieve_cache)))
            
            # 只处理从原max_cached的平方根到新n的平方根之间的奇数
            start_i = max(3, int(sqrt(max_cached)) + 1)
            # 确保起始i是奇数
            if start_i % 2 == 0:
                start_i += 1
            
            for i in range(start_i, int(sqrt(n)) + 1, 2):
                if sieve_cache[i // 2]:
                    # 标记倍数的起始位置:取i²和max_cached+1中的较大值,且保证是奇数
                    start = max(i*i, max_cached + 1)
                    if start % 2 == 0:
                        start += 1
                    start_idx = start // 2
                    # 计算需要标记的元素数量,批量赋值为False
                    sieve_cache[start_idx::i] = [False] * ((n - start - 1) // (2*i) + 1)
            
            # 收集新增的质数(从max_cached之后的奇数中筛选)
            new_primes_start = ((max_cached - 1) // 2) + 1
            new_primes = [2*i + 1 for i in range(new_primes_start, n//2) if sieve_cache[i]]
            primes_cache.extend(new_primes)
            max_cached = n
            return tuple(primes_cache)
    
    return sieve

# 使用示例
sieve = cached_sieve()

使用测试

你可以这样测试缓存的效果:

# 第一次调用,生成并缓存小于10的质数
print(sieve(10))  # 输出: (2, 3, 5, 7)

# 调用n=5,直接复用缓存切片
print(sieve(5))   # 输出: (2, 3)

# 调用n=20,增量扩展筛子到20,新增11,13,17,19
print(sieve(20))  # 输出: (2, 3, 5, 7, 11, 13, 17, 19)

关键细节说明

  • 用闭包维护缓存,避免了全局变量的副作用,同时保持状态的持续性
  • 增量扩展时只处理必要的奇数范围,不会重复计算已筛过的部分,保证了效率
  • 完全兼容你原代码的空间优化逻辑(只存储奇数的标记),不会额外增加内存开销

备注:内容来源于stack exchange,提问作者jonnybolton16

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:44:49