aboutsummaryrefslogtreecommitdiff
path: root/2024/heap.lisp
blob: 62d36fbba56ce067f8a0a00424274763fe1bf655 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
(defpackage #:heap
  (:use :cl)
  (:export :dequeue :emptyp :enqueue :make-heap))

(in-package #:heap)

(defun make-heap (&key (priority-function #'identity))
  (cons (make-array 0 :fill-pointer t) priority-function))

(defun enqueue (item heap)
  (let ((heap-vec (car heap)))
    (vector-push-extend item heap-vec)
    (%sift-down heap 0 (1- (length heap-vec)))))

(defun dequeue (heap)
  (let* ((heap-vec (car heap))
         (last-item (vector-pop heap-vec)))
    (if (zerop (length heap-vec))
        last-item
        (prog1
            (aref heap-vec 0)
          (setf (aref heap-vec 0) last-item)
          (%sift-up heap 0)))))

(defun emptyp (heap)
  (zerop (length (car heap))))

(defun %sift-down (heap start-pos pos)
  (let* ((heap-vec (car heap))
         (heap-fn (cdr heap))
         (new-item (aref heap-vec pos)))
    (loop while (> pos start-pos) do
      (let* ((parent-pos (ash (1- pos) -1))
             (parent (aref heap-vec parent-pos)))
        (unless (< (funcall heap-fn new-item)
                   (funcall heap-fn parent))
          (loop-finish))
        (setf (aref heap-vec pos) parent)
        (setq pos parent-pos)))
    (setf (aref heap-vec pos) new-item)))

(defun %sift-up (heap pos)
  (let* ((heap-vec (car heap))
         (heap-fn (cdr heap))
         (end-pos (length heap-vec))
         (start-pos pos)
         (new-item (aref heap-vec pos))
         (child-pos (1+ (* 2 pos))))
    (loop while (< child-pos end-pos) do
      (let ((right-pos (1+ child-pos)))
        (when (and (< right-pos end-pos)
                   (>= (funcall heap-fn (aref heap-vec child-pos))
                       (funcall heap-fn (aref heap-vec right-pos))))
          (setq child-pos right-pos))
        (setf (aref heap-vec pos) (aref heap-vec child-pos))
        (setq pos child-pos
              child-pos (1+ (* 2 pos)))))
    (setf (aref heap-vec pos) new-item)
    (%sift-down heap start-pos pos)))