UNPKG

6.74 kBJavaScriptView Raw
1(function() {
2 var Heap, defaultCmp, floor, heapify, heappop, heappush, heappushpop, heapreplace, insort, min, nlargest, nsmallest, _siftdown, _siftup;
3
4 floor = Math.floor, min = Math.min;
5
6 /*
7 Insert item x in list a, and keep it sorted assuming a is sorted.
8
9 If x is already in a, insert it to the right of the rightmost x.
10
11 Optional args lo (default 0) and hi (default a.length) bound the slice
12 of a to be searched.
13 */
14
15 insort = function(a, x, lo, hi) {
16 var mid;
17 if (lo == null) lo = 0;
18 if (lo < 0) throw new Error('lo must be non-negative');
19 if (hi == null) hi = a.length;
20 while (lo < hi) {
21 mid = floor((lo + hi) / 2);
22 if (x < a[mid]) {
23 hi = mid;
24 } else {
25 lo = mid + 1;
26 }
27 }
28 return ([].splice.apply(a, [lo, lo - lo].concat(x)), x);
29 };
30
31 /*
32 Default comparison function to be used
33 */
34
35 defaultCmp = function(x, y) {
36 if (x < y) return -1;
37 if (x > y) return 1;
38 return 0;
39 };
40
41 /*
42 Push item onto heap, maintaining the heap invariant.
43 */
44
45 heappush = function(array, item, cmp) {
46 if (cmp == null) cmp = defaultCmp;
47 array.push(item);
48 return _siftdown(array, 0, array.length - 1, cmp);
49 };
50
51 /*
52 Pop the smallest item off the heap, maintaining the heap invariant.
53 */
54
55 heappop = function(array, cmp) {
56 var lastelt, returnitem;
57 if (cmp == null) cmp = defaultCmp;
58 lastelt = array.pop();
59 if (array.length) {
60 returnitem = array[0];
61 array[0] = lastelt;
62 _siftup(array, 0, cmp);
63 } else {
64 returnitem = lastelt;
65 }
66 return returnitem;
67 };
68
69 /*
70 Pop and return the current smallest value, and add the new item.
71
72 This is more efficient than heappop() followed by heappush(), and can be
73 more appropriate when using a fixed size heap. Note that the value
74 returned may be larger than item! That constrains reasonable use of
75 this routine unless written as part of a conditional replacement:
76 if item > array[0]
77 item = heapreplace(array, item)
78 */
79
80 heapreplace = function(array, item, cmp) {
81 var returnitem;
82 if (cmp == null) cmp = defaultCmp;
83 returnitem = array[0];
84 array[0] = item;
85 _siftup(array, 0, cmp);
86 return returnitem;
87 };
88
89 /*
90 Fast version of a heappush followed by a heappop.
91 */
92
93 heappushpop = function(array, item, cmp) {
94 var _ref;
95 if (cmp == null) cmp = defaultCmp;
96 if (array.length && cmp(array[0], item) < 0) {
97 _ref = [array[0], item], item = _ref[0], array[0] = _ref[1];
98 _siftup(array, 0, cmp);
99 }
100 return item;
101 };
102
103 /*
104 Transform list into a heap, in-place, in O(array.length) time.
105 */
106
107 heapify = function(array, cmp) {
108 var i, _i, _j, _len, _ref, _ref2, _results, _results2;
109 if (cmp == null) cmp = defaultCmp;
110 _ref2 = (function() {
111 _results2 = [];
112 for (var _j = 0, _ref = floor(array.length / 2); 0 <= _ref ? _j < _ref : _j > _ref; 0 <= _ref ? _j++ : _j--){ _results2.push(_j); }
113 return _results2;
114 }).apply(this).reverse();
115 _results = [];
116 for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
117 i = _ref2[_i];
118 _results.push(_siftup(array, i, cmp));
119 }
120 return _results;
121 };
122
123 /*
124 Find the n largest elements in a dataset.
125 */
126
127 nlargest = function(n, array, cmp) {
128 var elem, result, _i, _len, _ref;
129 if (cmp == null) cmp = defaultCmp;
130 result = array.slice(0, n);
131 if (!result.length) return result;
132 heapify(result, cmp);
133 _ref = array.slice(n);
134 for (_i = 0, _len = _ref.length; _i < _len; _i++) {
135 elem = _ref[_i];
136 heappushpop(result, elem, cmp);
137 }
138 return result.sort(cmp).reverse();
139 };
140
141 /*
142 Find the n smallest elements in a dataset.
143 */
144
145 nsmallest = function(n, array, cmp) {
146 var elem, i, los, result, _i, _len, _ref, _results;
147 if (cmp == null) cmp = defaultCmp;
148 if (n * 10 <= array.length) {
149 result = array.slice(0, n + 1 || 9e9).sort();
150 if (!result.length) return result;
151 los = result[result.length - 1];
152 for (_i = 0, _len = array.length; _i < _len; _i++) {
153 elem = array[_i];
154 if (cmp(elem, los) < 0) {
155 insort(result, elem);
156 result.pop();
157 los = result[result.length - 1];
158 }
159 }
160 return result;
161 }
162 heapify(array, cmp);
163 _results = [];
164 for (i = 0, _ref = min(n, array.length); 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
165 _results.push(heappop(array, cmp));
166 }
167 return _results;
168 };
169
170 _siftdown = function(array, startpos, pos, cmp) {
171 var newitem, parent, parentpos;
172 if (cmp == null) cmp = defaultCmp;
173 newitem = array[pos];
174 while (pos > startpos) {
175 parentpos = (pos - 1) >> 1;
176 parent = array[parentpos];
177 if (cmp(newitem, parent) < 0) {
178 array[pos] = parent;
179 pos = parentpos;
180 continue;
181 }
182 break;
183 }
184 return array[pos] = newitem;
185 };
186
187 _siftup = function(array, pos, cmp) {
188 var childpos, endpos, newitem, rightpos, startpos;
189 if (cmp == null) cmp = defaultCmp;
190 endpos = array.length;
191 startpos = pos;
192 newitem = array[pos];
193 childpos = 2 * pos + 1;
194 while (childpos < endpos) {
195 rightpos = childpos + 1;
196 if (rightpos < endpos && !(cmp(array[childpos], array[rightpos]) < 0)) {
197 childpos = rightpos;
198 }
199 array[pos] = array[childpos];
200 pos = childpos;
201 childpos = 2 * pos + 1;
202 }
203 array[pos] = newitem;
204 return _siftdown(array, startpos, pos, cmp);
205 };
206
207 Heap = (function() {
208
209 Heap.push = heappush;
210
211 Heap.pop = heappop;
212
213 Heap.replace = heapreplace;
214
215 Heap.pushpop = heappushpop;
216
217 Heap.heapify = heapify;
218
219 Heap.nlargest = nlargest;
220
221 Heap.nsmallest = nsmallest;
222
223 function Heap(cmp) {
224 this.cmp = cmp != null ? cmp : defaultCmp;
225 this.data = [];
226 }
227
228 Heap.prototype.push = function(x) {
229 return heappush(this.data, x, this.cmp);
230 };
231
232 Heap.prototype.pop = function() {
233 return heappop(this.data, this.cmp);
234 };
235
236 Heap.prototype.replace = function(x) {
237 return heapreplace(this.data, x, this.cmp);
238 };
239
240 Heap.prototype.pushpop = function(x) {
241 return heappushpop(this.data, x, this.cmp);
242 };
243
244 Heap.prototype.heapify = function() {
245 return heapify(this.data, this.cmp);
246 };
247
248 Heap.prototype.empty = function() {
249 return this.data.length === 0;
250 };
251
252 Heap.prototype.size = function() {
253 return this.data.length;
254 };
255
256 Heap.prototype.toArray = function() {
257 return this.data.slice();
258 };
259
260 return Heap;
261
262 })();
263
264 ((typeof module !== "undefined" && module !== null ? module.exports : void 0) || window).Heap = Heap;
265
266}).call(this);