-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathheap.lisp
More file actions
120 lines (106 loc) · 4.21 KB
/
heap.lisp
File metadata and controls
120 lines (106 loc) · 4.21 KB
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
(in-package :com.search)
(defstruct heap
less-fn
order
a
max-count)
(defun percolate-down (heap hole x)
"Private. Move the HOLE down until it's in a location suitable for X.
Return the new index of the hole."
(do ((a (heap-a heap))
(less (heap-less-fn heap))
(child (lesser-child heap hole) (lesser-child heap hole)))
((or (>= child (fill-pointer a)) (funcall less x (aref a child)))
hole)
(setf (aref a hole) (aref a child)
hole child)))
(defun percolate-up (heap hole x)
"Private. Moves the HOLE until it's in a location suitable for holding
X. Does not actually bind X to the HOLE. Returns the new
index of the HOLE. The hole itself percolates down; it's the X
that percolates up."
(let ((d (heap-order heap))
(a (heap-a heap))
(less (heap-less-fn heap)))
(setf (aref a 0) x)
(do ((i hole parent)
(parent (floor (/ hole d)) (floor (/ parent d))))
((not (funcall less x (aref a parent))) i)
(setf (aref a i) (aref a parent)))))
(defun heap-init (heap less-fn &key (order 2) (initial-contents nil))
"Initialize the indicated heap. If INITIAL-CONTENTS is a non-empty
list, the heap's contents are intiailized to the values in that
list; they are ordered according to LESS-FN. INITIAL-CONTENTS must
be a list or NIL."
(setf (heap-less-fn heap) less-fn
(heap-order heap) order
(heap-a heap) (make-array 2 :initial-element nil
:adjustable t :fill-pointer 1)
(heap-max-count heap) 0)
(when initial-contents
(dolist (i initial-contents) (vector-push-extend i (heap-a heap)))
(loop for i from (floor (/ (length (heap-a heap)) order)) downto 1
do (let* ((tmp (aref (heap-a heap) i))
(hole (percolate-down heap i tmp)))
(setf (aref (heap-a heap) hole) tmp)))
(setf (heap-max-count heap) (length (heap-a heap))))
heap)
(defun create-heap (less-fn &key (order 2) (initial-contents nil))
(heap-init (make-heap) less-fn :order order
:initial-contents initial-contents))
(defun heap-clear (heap)
"Remove all elements from the heap, leaving it empty. Faster
(& more convenient) than calling HEAP-REMOVE until the heap is
empty."
(setf (fill-pointer (heap-a heap)) 1)
nil)
(defun heap-count (heap)
(1- (fill-pointer (heap-a heap))))
(defun heap-empty-p (heap)
"Returns non-NIL if & only if the heap contains no items."
(= (fill-pointer (heap-a heap)) 1))
(defun heap-insert (heap x)
"Insert a new element into the heap. Return the element (which probably
isn't very useful)."
(let ((a (heap-a heap)))
;; Append a hole for the new element.
(vector-push-extend nil a)
;; Move the hole from the end towards the front of the
;; queue until it is in the right position for the new
;; element.
(setf (aref a (percolate-up heap (1- (fill-pointer a)) x)) x)))
(defun heap-find-idx (heap fnp)
"Return the index of the element which satisfies the predicate FNP.
If there is no such element, return the fill pointer of HEAP's array A."
(do* ((a (heap-a heap))
(fp (fill-pointer a))
(i 1 (1+ i)))
((or (>= i fp) (funcall fnp heap (aref a i)))
i)))
(defun heap-remove (heap &optional (fn #'(lambda (h x) (declare (ignore h x)) t)))
"Remove the minimum (first) element in the heap & return it. It's
an error if the heap is already empty. (Should that be an error?)"
(let ((a (heap-a heap))
(i (heap-find-idx heap fn)))
(cond ((< i (fill-pointer a));; We found an element to remove.
(let ((x (aref a i))
(last-object (vector-pop a)))
(setf (aref a (percolate-down heap i last-object)) last-object)
x))
(t nil))));; Nothing to remove
(defun heap-peek (heap)
"Return the first element in the heap, but don't remove it. It'll
be an error if the heap is empty. (Should that be an error?)"
(aref (heap-a heap) 1))
(defun lesser-child (heap parent)
"Return the index of the lesser child. If there's one child,
return its index. If there are no children, return
(FILL-POINTER (HEAP-A HEAP))."
(let* ((a (heap-a heap))
(left (* parent (heap-order heap)))
(right (1+ left))
(fp (fill-pointer a)))
(cond ((>= left fp) fp)
((= right fp) left)
((funcall (heap-less-fn heap) (aref a left) (aref a right)) left)
(t right))))