My implementation is based on the incremental prime sieve described on Wikipedia. I'm relatively new to lisp so I would appreciate any comments on my coding style or on the algorithm.
The below code implements a min-heap and uses it in the prime number generation algorithm:
(defstruct heap
; (cmp x y) should return true if x is less than y.
(cmp '())
(arr '())
(size 0))
(defun resize (heap)
(let* ((old-arr (heap-arr heap))
(old-cap (length old-arr))
(new-cap (max 10 (* 2 old-cap)))
(new-arr (make-array (list new-cap))))
(loop for i from 0 to (- old-cap 1)
do (setf (aref new-arr i) (aref old-arr i)))
(setf (heap-arr heap) new-arr)))
(defun insert (x heap)
(let ((size (heap-size heap))
(cmp (heap-cmp heap)))
(when (= size (length (heap-arr heap)))
(resize heap))
(setf (aref (heap-arr heap) size) x)
(setf (heap-size heap) (+ 1 size))
(loop with arr = (heap-arr heap)
for i = size then parent
for parent = (floor (- i 1) 2)
while (and (> i 0)
(funcall cmp x (aref arr parent)))
do (setf (aref arr i) (aref arr parent))
(setf (aref arr parent) x))))
(defun peek (heap)
(aref (heap-arr heap) 0))
(defun extract (heap)
(let* ((arr (heap-arr heap))
(cmp (heap-cmp heap))
(size (heap-size heap))
(x (aref arr 0)))
(setf (heap-size heap) (- size 1))
(when (> size 1)
(setf (aref arr 0) (aref arr (- size 1)))
(loop for i = 0 then small-child-idx
for child1-idx = (+ 1 (* 2 i))
and child2-idx = (+ 2 (* 2 i))
for small-child-idx = (if (and (< child2-idx (heap-size heap))
(funcall cmp (aref arr child2-idx)
(aref arr child1-idx)))
child2-idx
child1-idx)
while (and (< child1-idx (heap-size heap))
(funcall cmp (aref arr small-child-idx) (aref arr i)))
do (let ((tmp (aref arr i)))
(setf (aref arr i) (aref arr small-child-idx))
(setf (aref arr small-child-idx) tmp))))
x))
(defun primes ()
(format t "3~%")
(loop with multiples = (make-heap :cmp (lambda (x y) (< (car x) (car y))))
initially (insert '(9 . 3) multiples)
for n from 5 by 2
if (< n (car (peek multiples)))
do (format t "~d~%" n)
(insert (cons (* n n) n) multiples)
else
do (loop while (= n (car (peek multiples)))
do (let* ((pair (extract multiples))
(m (car pair))
(p (cdr pair)))
(insert (cons (+ m (* 2 p)) p) multiples)))))
(primes)
1-
and1+
exist. \$\endgroup\$