-
Notifications
You must be signed in to change notification settings - Fork 172
/
Copy pathHeap.carp
197 lines (163 loc) · 6.42 KB
/
Heap.carp
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
; Abstract heap with user-supplied ordering function
; an ordering function is a binary relation
; `<` will create a MinHeap, `>` will create a MaxHeap
;
; for any two items `a` and `b`,
; `a` will be higher in the Heap then `b` if `(ord a b)`
(doc Heap "is a heap data structure that uses a user-supplied ordering function
to order its values.")
(defmodule Heap
(hidden lchild)
(defn lchild [i]
(+ 1 (* 2 i)))
(hidden rchild)
(defn rchild [i]
(+ 2 (* 2 i)))
(hidden parent)
(defn parent [i]
(/ (- i 1) 2))
(hidden max-of-three-until!)
(doc max-of-three-until! "Get the index for the largest (by ord) of an element and its two children.")
(defn max-of-three-until! [heap i len ord]
(let-do [lchild-i (lchild i)
rchild-i (rchild i)]
(when (and (< lchild-i len) (~ord (Array.unsafe-nth heap lchild-i) (Array.unsafe-nth heap i)))
(set! i lchild-i))
(when (and (< rchild-i len) (~ord (Array.unsafe-nth heap rchild-i) (Array.unsafe-nth heap i)))
(set! i rchild-i))
i))
; push-down-until!, push-down!, and push-up! are intended for use only by
; those performing internal mutation to the heap who want to restore order.
(defn push-down-until! [heap i len ord]
(while true
(let [challenger (max-of-three-until! heap i len ord)]
(if (= challenger i)
(break)
(do
(Array.swap! heap i challenger)
(set! i challenger))))))
(defn push-down! [heap i ord]
(push-down-until! heap i (Array.length heap) ord))
(defn push-up! [heap i ord]
(while (/= i 0)
(let [elem (Array.unsafe-nth heap i)
parent-i (Heap.parent i)
parent-elem (Array.unsafe-nth heap parent-i)]
(if (not (~ord elem parent-elem))
(break)
(do (Array.swap! heap i parent-i)
(set! i parent-i))))))
(doc peek "Returns first item on heap.")
(defn peek [heap]
(Array.first heap))
(doc heapify! "Convert array to a heap in place")
(defn heapify! [arr ord]
(let [len (Array.length arr)]
(for [i 1 len]
(push-up! arr i ord))))
(doc push! "Insert a new item onto the heap.")
(defn push! [heap item ord]
(do
(Array.push-back! heap item)
(push-up! heap (- (Array.length heap) 1) ord)))
(doc pop! "Remove and return the first item in the heap.")
(defn pop! [heap ord]
(do
; swap 0 with tail
(Array.swap! heap 0 (- (Array.length heap) 1))
; restore heap excluding tail
(push-down-until! heap 0 (- (Array.length heap) 1) ord)
; pop off tail, returning it
(Array.pop-back! heap)))
)
(doc MinHeap "is a heap that uses `<` to order its values.")
(defmodule MinHeap
(hidden ord)
(defn ord [a b]
(< a b))
(defn push-down! [heap i]
(Heap.push-down! heap i &ord))
(defn push-down-until! [heap i len]
(Heap.push-down-until! heap i len &ord))
(defn push-up! [heap i]
(Heap.push-up! heap i &ord))
(doc peek "Returns minimum item on min-heap.")
(defn peek [heap]
(Array.first heap))
(doc heapify! "Convert array to a min-heap in place")
(defn heapify! [arr]
(Heap.heapify! arr &ord))
(doc push! "Insert a new element onto the min-heap.")
(defn push! [heap item]
(Heap.push! heap item &ord))
(doc pop! "Remove and return the first item in the min-heap.")
(defn pop! [heap]
(Heap.pop! heap &ord))
)
(doc MaxHeap "is a heap that uses `>` to order its values.")
(defmodule MaxHeap
(hidden ord)
(defn ord [a b]
(> a b))
(defn push-down! [heap i]
(Heap.push-down! heap i &ord))
(defn push-down-until! [heap i len]
(Heap.push-down-until! heap i len &ord))
(defn push-up! [heap i]
(Heap.push-up! heap i &ord))
(doc peek "Returns maximum first item on max-heap.")
(defn peek [heap]
(Array.first heap))
(doc heapify! "Convert array to a max-heap in place")
(defn heapify! [arr]
(Heap.heapify! arr &ord))
(doc push! "Insert a new element onto the max-heap.")
(defn push! [heap item]
(Heap.push! heap item &ord))
(doc pop! "Remove and return the first item in the max-heap.")
(defn pop! [heap]
(Heap.pop! heap &ord))
)
(doc HeapSort "is a module for sorting using the heap data structure.")
(defmodule HeapSort
(hidden ord)
(defn ord [a b]
(> a b))
(doc sort-by! "Perform an in-place heapsort of a given array with a comparison function.")
(defn sort-by! [arr f]
(do
(Heap.heapify! arr f)
; now we walk through the array, at all times 0..tail is a max heap
; and tail..len is the sorted output
; we slowly grow the tail while shrinking the head
; once tail == 0, then we have finished sorting
(let [tail (- (Array.length arr) 1)]
(while (> tail 0)
(do
; swap values of [0] and [tail]
; this makes our heap temporarily invalid
(Array.swap! arr 0 tail)
; keep pushing down 0 until heap property is satisfied
(Heap.push-down-until! arr 0 tail f)
; grow our tail, shrinking our head
(set! tail (- tail 1)))))))
(doc sorted-by "Perform a heapsort in a new copy of given array with comparison function.")
(defn sorted-by [arr f]
(let-do [narr (Array.copy arr)]
(sort-by! &narr f)
narr))
(doc sort-by "Perform an in-place heapsort of a given owned array with comparison function.")
(defn sort-by [arr f]
(do
(sort-by! &arr f)
arr))
(doc sort! "Perform an in-place heapsort of a given array.")
(defn sort! [arr]
(sort-by! arr &ord))
(doc sorted "Perform a heapsort in a new copy of given array.")
(defn sorted [arr]
(sorted-by arr &ord))
(doc sort "Perform an in-place heapsort of a given owned array.")
(defn sort [arr]
(sort-by arr &ord))
)