UNPKG

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