素数列表从2到n(方案)

时间:2013-10-31 00:25:02

标签: list numbers scheme primes

我正在尝试创建一个程序,用于构建从2到任意数字n的素数列表。当然,这需要迭代完成,但我不知道我做错了什么。

(define (list-2-to-n n)
    (define (iter n result)
        (if (= n 0)
            result
        (if (< n 2)
           '()
            (if (= (remainder n 3) 0)
                (list-2-to-n (- n 1))
            (if (even? n)
                (list-2-to-n (- n 1))
                (iter (- n 1) (cons n result)))))))

    (iter n '())) 

每当测试用例通过该过程时,它总是返回()

1 个答案:

答案 0 :(得分:1)

  

我做错了什么。

我们来看看。首先,你的缩进是令人遗憾的误导。它确实应该正确反映代码的结构:

(define (list-2-to-n-0 n)       ; a global function
    (define (iter n result)     ; an internal function
        (if (= n 0)             
            result
            (if (< n 2)                        ; **else**
               '()
                (if (= (remainder n 3) 0)
                    (list-2-to-n (- n 1))
                    (if (even? n)              ; **else**
                        (list-2-to-n (- n 1))
                        (iter (- n 1) (cons n result)))))))
    (iter n '())) 

如果没有,至少你应该用一些评论清楚地标明备选条款。

现在,您测试输入数字是否可被2或3整除,并以完全相同的方式响应。这两个案件应该真正加入一个案件。另外,我们可以在这里使用cond而不是那么多嵌套的if

(define (list-2-to-n-1 n)       ; a global function 
    (define (iter n result)     ; an internal function
        (cond
            ((= n 0)  result)
            ((< n 2)  '())
            ((or (= (remainder n 2) 0) (= (remainder n 3) 0))
              (list-2-to-n (- n 1))       ; calling a global function, and
            (else                         ;   returning its result
              (iter (- n 1)               ; calling internal function, and
                    (cons n result)))))   ;   returning its result
    (iter n '())) 

调用全局函数意味着重新启动整个过程 - 它将使用iter的初始累加器参数调用 ()。如果n==0的初始值高于0,那么n的假设结果返回情况实际上无法访问,因为首先会遇到n < 2个案例,()将会出现isPrime返回(完全是观察到的行为)。

你不应该重新开始,即你应该总是调用内部函数。你应该修复你的基础案例。最后但并非最不重要的是,只检查2或3的可分性是不够的,已经为5了。所以让我们在那里写(define (list-2-to-n-1 n) ; a global function (define (iter n result) ; an internal function (cond ((< n 2) result) ((not (isPrime n)) (iter (- n 1) result)) ; calling internal function, without (else ; altering the accumulator (iter (- n 1) ; calling internal function, (cons n result))))) ; altering the accumulator (iter n '())) ,并在以后实现它:

isPrime

n需要尝试将d除以2,3,...不需要尝试除以2以上的任何均值,只是赔率就足够了。不需要尝试d * d > n这样的任何潜在除数n = f * d, f <= d,因为如果f*d <= d*d那么n <= d*dn

当然,尝试除以9,15,77之类的任何组合也是多余的 - 如果其中任何一个除sqrt(k),那么其中一个主要因素3,5,7,11也将它分开,而我们会更早发现它们。所以实际上,尝试仅按素数划分就足够了。为了能够做到这一点,您需要重新构建代码,以便按升序构建其结果的素数列表,并使用不超过k的前缀部分来测试每个候选{{1}}。< / p>

这称为trial division算法。然后有一个更快sieve of Eratosthenes