我一直在网上搜索计划中的Eratosthenes Sieve的实现,虽然我想出了很多内容,但似乎没有一个像我需要它一样。
问题是大多数算法使用静态结束或使用迭代。这与我对语言缺乏了解导致我向你们所有人寻求帮助。
我需要一个Sieve的实现,它接受一个参数(直到Sieve的数字),仅使用递归并且具有一个带有#t
(true)或{{1的数字的“cons”列表(false)。
基本上算法就是这样:
示例输出:
> (erat-sieve 20)
((2. #t) (3. .t) (4。#f) (5. .t) (6. .f) (7。#t) (8。#f) (9。#f) (10. .f) (11. #t) (12. #f) (13. #t) (14。#f) (15。#f) (16。#f) (17。#t) (18。#f) (19。#t) (20。#f))
如果您还可以对评论进行彻底的解释,那将非常感激。
谢谢!
REVISED ::: 所以我已经学会了一些方案来进一步解释我的问题...
这就是列表。
#f
这将返回一个列表,其中除数的每个倍数都标记为false。
(define (makeList n)
(if (> n 2)
(append (makeList (- n 1)) (list (cons n (and))))
(list (cons 2 (and)))))
现在这是我遇到麻烦的功能,看起来它应该可以工作,我已经手动完成了三次,但我无法弄清楚为什么它不会返回我需要的东西。
(define (mark-off-multiples numbers divisor)
(if (null? numbers)
'()
(append
(list (cons (car (car numbers))
(not (zero? (modulo (car (car numbers)) divisor)))))
(mark-off-multiples (cdr numbers) divisor))))
我正在尝试做的是,正如函数名称所示,为列表中仍标记为true的每个数字调用mark-off-multiples。因此,您传入(define (call-mark-off-multiples-for-each-true-number numbers)
(if (null? numbers)
'()
(if (cdr (car numbers))
(append (list (car numbers))
(call-mark-off-multiples-for-each-true-number
(mark-off-multiples (cdr numbers) (car (car numbers)))))
(append (list (car numbers))
(call-mark-off-multiples-for-each-true-number
(cdr numbers))))))
,然后调用((3.#t)(4.#t)(5.#t))
获取2并返回mark-off-multiples
并向其追加(3.#t)(4.#f)(5.#t)
。然后它再次调用自己传递(2.#t)
并使用返回(3.#t)(4.#f)(5.#t)
的列表的 cdr 调用mark-off-multiples并继续沿着列表...
然后返回的输出是一个包含所有真实的列表。
这有希望帮助你更好地理解我的困境。
答案 0 :(得分:2)
这是一个有效的解决方案。
(define (divides? m n)
(if (eq? (modulo n m) 0)
#t
#f))
(define (mark-true n)
(cons n #t))
(define (mark-divisors n ns)
(cond ((null? ns) '())
((and (unmarked? (car ns))
(divides? n (car ns)))
(cons (cons (car ns) #f) (mark-divisors n (cdr ns))))
(else (cons (car ns) (mark-divisors n (cdr ns))))))
(define (unmarked? n)
(not (pair? n)))
(define (eratosthenes x)
(cond ((null? x) '())
((unmarked? (car x))
(cons (mark-true (car x))
(eratosthenes (mark-divisors (car x) (cdr x)))))
(else (cons (car x) (eratosthenes (cdr x))))))
(eratosthenes (list 2 3 4 5 6))
我已经使用了许多辅助函数,但如果你愿意,可以将它们添加到eratosthenes函数中。我认为它使整个业务更具可读性。
mark-true
将值赋予#t
。 mark-divisors
取n
个数字和一个数字列表,并将n
分成#f
的所有数字都包含在内。几乎其他一切都是自我解释的。 Eratosthenes按预期工作,如果第一个数字是“未标记”,则将其标记为“真实”或“素数”,然后从列表的其余部分“越过”其所有倍数,然后为每个后续“未标记”重复列表中的数字。我的eratosthenes功能基本上与你尝试用你的功能有关。我不确定你的问题是什么,但作为一项规则,帮助你制作更具可读性的东西是有帮助的。
我在DrRacket和Neil Van Dyke的SICP包中做到了这一点。我不知道你正在使用什么方案。如果您在使用此功能时遇到问题,请与我们联系。
答案 1 :(得分:1)
好的,所以SoE的重点不是测试任何可分性,而是一次只计算 p 数字:
(define (make-list n) ; list of unmarked numbers 2 ... n
(let loop ((i n)
(a '()))
(if (= i 1)
a ; (cons '(2 . #t) (cons (3 . #t) ... (list '(n . #t))...))
(loop (- i 1) (cons (cons i #t) a)))))
(define (skip2t xs) ; skip to first unmarked number
(if (cdar xs) xs (skip2t (cdr xs))))
(define (mark-each! k n i xs) ; destructive update of list xs -
(set-cdr! (car xs) #f) ; mark each k-th elem,
(if (<= (+ i k) n) ; head is i, last is n
(mark-each! k n (+ i k)
(list-tail xs k))))
(define (erat-sieve n)
(let ((r (sqrt n)) ; unmarked multiples start at prime's square
(xs (make-list n)))
(let loop ((a xs))
(let ((p (caar a))) ; next prime
(cond ((<= p r)
(mark-each! p n (* p p) (list-tail a (- (* p p) p)))
(loop (skip2t (cdr a)))))))
xs))
那样(erat-sieve 20) ==> ((2 . #t) (3 . #t) (4) (5 . #t) (6) (7 . #t) (8) (9) (10) (11 . #t) (12) (13 . #t) (14) (15) (16) (17 . #t) (18) (19 . #t) (20))
无界筛子,遵循公式
P = {3,5,7,9,...} \ U {{ p 2 , p 2 + 2p , p 2 + 4p , p 2 < / sup> + 6p ,...} | P }
中的 p可以使用SICP样式流定义(可以看到here):
;;;; Stream Implementation
(define (head s) (car s))
(define (tail s) ((cdr s)))
(define-syntax s-cons
(syntax-rules () ((s-cons h t) (cons h (lambda () t)))))
;;;; Stream Utility Functions
(define (from-By x s)
(s-cons x (from-By (+ x s) s)))
(define (take n s)
(cond ((= n 0) '())
((= n 1) (list (car s)))
(else (cons (head s) (take (- n 1) (tail s))))))
(define (drop n s)
(cond ((> n 0) (drop (- n 1) (tail s)))
(else s)))
(define (s-map f s)
(s-cons (f (head s)) (s-map f (tail s))))
(define (s-diff s1 s2)
(let ((h1 (head s1)) (h2 (head s2)))
(cond
((< h1 h2) (s-cons h1 (s-diff (tail s1) s2 )))
((< h2 h1) (s-diff s1 (tail s2)))
(else (s-diff (tail s1) (tail s2))))))
(define (s-union s1 s2)
(let ((h1 (head s1)) (h2 (head s2)))
(cond
((< h1 h2) (s-cons h1 (s-union (tail s1) s2 )))
((< h2 h1) (s-cons h2 (s-union s1 (tail s2))))
(else (s-cons h1 (s-union (tail s1) (tail s2)))))))
;;;; odd multiples of an odd prime
(define (mults p) (from-By (* p p) (* 2 p)))
;;;; The Sieve itself, bounded, ~ O(n^1.4) in n primes produced
;;;; (unbounded version runs at ~ O(n^2.2), and growing worse)
;;;; **only valid up to m**, includes composites above it !!NB!!
(define (primes-To m)
(define (sieve s)
(let ((p (head s)))
(cond ((> (* p p) m) s)
(else (s-cons p
(sieve (s-diff (tail s) (mults p))))))))
(s-cons 2 (sieve (from-By 3 2))))
;;;; all the primes' multiples, tree-merged, removed;
;;;; ~O(n^1.17..1.15) time in producing 100K .. 1M primes
;;;; ~O(1) space (O(pi(sqrt(m))) probably)
(define (primes-TM)
(define (no-mults-From from)
(s-diff (from-By from 2) (s-tree-join (s-map mults odd-primes))))
(define odd-primes
(s-cons 3 (no-mults-From 5)))
(s-cons 2 (no-mults-From 3)))
;;;; join an ordered stream of streams (here, of primes' multiples)
;;;; into one ordered stream, via an infinite right-deepening tree
(define (s-tree-join sts) ;; sts -> s
(define (join-With of-Tail sts) ;; sts -> s
(s-cons (head (head sts))
(s-union (tail (head sts)) (of-Tail (tail sts)))))
(define (pairs sts) ;; sts -> sts
(s-cons (join-With head sts) (pairs (tail (tail sts)))))
(join-With (lambda (t) (s-tree-join (pairs t))) sts))
;;;; Print 10 last primes from the first thousand primes
(begin
(newline)
(display (take 10 (drop 990 (primes-To 7919)))) (newline)
(display (take 10 (drop 990 (primes-TM)))) (newline))
在麻省理工学院计划中测试。
答案 2 :(得分:1)
(define (prime-sieve-to n)
(let* ((sz (quotient n 2)) (sv (make-vector sz 1)) (lm (integer-sqrt n)))
(for ((i (in-range 1 lm)))
(cond ((vector-ref sv i)
(let ((v (+ 1 (* 2 i))))
(for ((i (in-range (+ i (* v (/ (- v 1) 2))) sz v)))
(vector-set! sv i 0))))))
(cons 2
(for/list ((i (in-range 1 sz))
#:when (and (> (vector-ref sv i) 0) (> i 0)))
(+ 1 (* 2 i))))))
这是另一个方案的球拍方言,但有效率高达100,000,000。在此之上,我不会保证其效率。
答案 3 :(得分:0)
代码和解释可以在SICP 3.5.2Infinite Streams中找到 http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#%_sec_3.5.2