-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathqueue.lisp
More file actions
140 lines (117 loc) · 5.03 KB
/
queue.lisp
File metadata and controls
140 lines (117 loc) · 5.03 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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
https://powcoder.com
代写代考加微信 powcoder
Assignment Project Exam Help
Add WeChat powcoder
https://powcoder.com
代写代考加微信 powcoder
Assignment Project Exam Help
Add WeChat powcoder
;;; -*- Mode: Lisp; Syntax: Common-Lisp; -*- File: utilities/queue.lisp
;;;; The Queue datatype
;;; We can remove elements form the front of a queue. We can add elements in
;;; three ways: to the front, to the back, or ordered by some numeric score.
;;; This is done with the following enqueing functions, which make use of the
;;; following implementations of the elements:
;;; ENQUEUE-AT-FRONT - elements are a list
;;; ENQUEUE-AT-END - elements are a list, with a pointer to end
;;; ENQUEUE-BY-PRIORITY - elements are a heap, implemented as an array
;;; The best element in the queue is always in position 0.
;;; The heap implementation is taken from "Introduction to Algorithms" by
;;; Cormen, Lieserson & Rivest [CL&R], Chapter 7. We could certainly speed
;;; up the constant factors of this implementation. It is meant to be clear
;;; and simple and O(log n), but not super efficient. Consider a Fibonacci
;;; heap [Page 420 CL&R] if you really have large queues to deal with.
(defstruct q
(key #'identity)
(last nil)
(elements nil))
;;;; Basic Operations on Queues
(defun make-empty-queue () (make-q))
(defun empty-queue? (q)
"Are there no elements in the queue?"
(= (length (q-elements q)) 0))
(defun queue-front (q)
"Return the element at the front of the queue."
(elt (q-elements q) 0))
(defun remove-front (q)
"Remove the element from the front of the queue and return it."
(if (listp (q-elements q))
(pop (q-elements q))
(heap-extract-min (q-elements q) (q-key q))))
;;;; The Three Enqueing Functions
(defun enqueue-at-front (q &rest items)
"Add a list of items to the front of the queue."
(setf (q-elements q) (nconc items (q-elements q))))
(defun enqueue-at-end (q &rest items)
"Add a list of items to the end of the queue."
;; To make this more efficient, keep a pointer to the last cons in the queue
(cond ((null items) nil)
((or (null (q-last q)) (null (q-elements q)))
(setf (q-last q) (last items)
(q-elements q) (nconc (q-elements q) items)))
(t (setf (cdr (q-last q)) items
(q-last q) (last items)))))
(defun enqueue-by-priority (q key &rest items)
"Insert the items by priority according to the key function."
;; First make sure the queue is in a consistent state
(setf (q-key q) key)
(when (null (q-elements q))
(setf (q-elements q) (make-heap)))
;; Now insert the items
(for each item in items do
(heap-insert (q-elements q) item key)))
;;;; The Heap Implementation of Priority Queues
;;; The idea is to store a heap in an array so that the heap property is
;;; maintained for all elements: heap[Parent(i)] <= heap[i]. Note that we
;;; start at index 0, not 1, and that we put the lowest value at the top of
;;; the heap, not the highest value.
;; These could be made inline
(defun heap-val (heap i key) (declare (fixnum i)) (funcall key (aref heap i)))
(defun heap-parent (i) (declare (fixnum i)) (floor (- i 1) 2))
(defun heap-left (i) (declare (fixnum i)) (the fixnum (+ 1 i i)))
(defun heap-right (i) (declare (fixnum i)) (the fixnum (+ 2 i i)))
(defun heapify (heap i key)
"Assume that the children of i are heaps, but that heap[i] may be
larger than its children. If it is, move heap[i] down where it belongs.
[Page 143 CL&R]."
(let ((l (heap-left i))
(r (heap-right i))
(N (- (length heap) 1))
smallest)
(setf smallest (if (and (<= l N) (<= (heap-val heap l key)
(heap-val heap i key)))
l i))
(if (and (<= r N) (<= (heap-val heap r key) (heap-val heap smallest key)))
(setf smallest r))
(when (/= smallest i)
(rotatef (aref heap i) (aref heap smallest))
(heapify heap smallest key))))
(defun heap-extract-min (heap key)
"Pop the best (lowest valued) item off the heap. [Page 150 CL&R]."
(let ((min (aref heap 0)))
(setf (aref heap 0) (aref heap (- (length heap) 1)))
(decf (fill-pointer heap))
(heapify heap 0 key)
min))
(defun heap-insert (heap item key)
"Put an item into a heap. [Page 150 CL&R]."
;; Note that ITEM is the value to be inserted, and KEY is a function
;; that extracts the numeric value from the item.
(vector-push-extend nil heap)
(let ((i (- (length heap) 1))
(val (funcall key item)))
(while (and (> i 0) (>= (heap-val heap (heap-parent i) key) val))
do (setf (aref heap i) (aref heap (heap-parent i))
i (heap-parent i)))
(setf (aref heap i) item)))
(defun make-heap (&optional (size 100))
(make-array size :fill-pointer 0 :adjustable t))
(defun heap-sort (numbers &key (key #'identity))
"Return a sorted list, with elements that are < according to key first."
;; Mostly for testing the heap implementation
;; There are more efficient ways of sorting (even of heap-sorting)
(let ((heap (make-heap))
(result nil))
(for each n in numbers do (heap-insert heap n key))
(while (> (length heap) 0) do (push (heap-extract-min heap key) result))
(nreverse result)))