articulated 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- package/build/commonjs/id_list.d.ts +56 -20
- package/build/commonjs/id_list.js +207 -107
- package/build/commonjs/id_list.js.map +1 -1
- package/build/commonjs/internal/leaf_map.d.ts +25 -0
- package/build/commonjs/internal/leaf_map.js +54 -0
- package/build/commonjs/internal/leaf_map.js.map +1 -0
- package/build/commonjs/internal/seq_map.d.ts +20 -0
- package/build/commonjs/internal/seq_map.js +40 -0
- package/build/commonjs/internal/seq_map.js.map +1 -0
- package/build/commonjs/vendor/functional-red-black-tree.d.ts +8 -0
- package/build/commonjs/vendor/functional-red-black-tree.js +911 -0
- package/build/commonjs/vendor/functional-red-black-tree.js.map +1 -0
- package/build/esm/id_list.d.ts +56 -20
- package/build/esm/id_list.js +206 -105
- package/build/esm/id_list.js.map +1 -1
- package/build/esm/internal/leaf_map.d.ts +25 -0
- package/build/esm/internal/leaf_map.js +47 -0
- package/build/esm/internal/leaf_map.js.map +1 -0
- package/build/esm/internal/seq_map.d.ts +20 -0
- package/build/esm/internal/seq_map.js +32 -0
- package/build/esm/internal/seq_map.js.map +1 -0
- package/build/esm/vendor/functional-red-black-tree.d.ts +8 -0
- package/build/esm/vendor/functional-red-black-tree.js +911 -0
- package/build/esm/vendor/functional-red-black-tree.js.map +1 -0
- package/package.json +10 -5
- package/src/id_list.ts +306 -109
- package/src/internal/leaf_map.ts +57 -0
- package/src/internal/seq_map.ts +48 -0
- package/src/vendor/functional-red-black-tree.d.ts +177 -0
- package/src/vendor/functional-red-black-tree.js +938 -0
|
@@ -0,0 +1,938 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
module.exports = createRBTree;
|
|
4
|
+
|
|
5
|
+
// Modified from https://github.com/mikolalysenko/functional-red-black-tree/blob/master/rbtree.js
|
|
6
|
+
// which is MIT Licensed, Copyright (c) 2013 Mikola Lysenko.
|
|
7
|
+
|
|
8
|
+
var RED = 0;
|
|
9
|
+
var BLACK = 1;
|
|
10
|
+
|
|
11
|
+
function RBNode(color, key, value, left, right) {
|
|
12
|
+
this._color = color;
|
|
13
|
+
this.key = key;
|
|
14
|
+
this.value = value;
|
|
15
|
+
this.left = left;
|
|
16
|
+
this.right = right;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function cloneNode(node) {
|
|
20
|
+
return new RBNode(node._color, node.key, node.value, node.left, node.right);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function repaint(color, node) {
|
|
24
|
+
return new RBNode(color, node.key, node.value, node.left, node.right);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function RedBlackTree(compare, root) {
|
|
28
|
+
this._compare = compare;
|
|
29
|
+
this.root = root;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var proto = RedBlackTree.prototype;
|
|
33
|
+
|
|
34
|
+
// Object.defineProperty(proto, "keys", {
|
|
35
|
+
// get: function () {
|
|
36
|
+
// var result = [];
|
|
37
|
+
// this.forEach(function (k, v) {
|
|
38
|
+
// result.push(k);
|
|
39
|
+
// });
|
|
40
|
+
// return result;
|
|
41
|
+
// },
|
|
42
|
+
// });
|
|
43
|
+
|
|
44
|
+
// Object.defineProperty(proto, "values", {
|
|
45
|
+
// get: function () {
|
|
46
|
+
// var result = [];
|
|
47
|
+
// this.forEach(function (k, v) {
|
|
48
|
+
// result.push(v);
|
|
49
|
+
// });
|
|
50
|
+
// return result;
|
|
51
|
+
// },
|
|
52
|
+
// });
|
|
53
|
+
|
|
54
|
+
//Set a key-value pair
|
|
55
|
+
proto.set = function (key, value) {
|
|
56
|
+
var cmp = this._compare;
|
|
57
|
+
//Find point to insert/replace node
|
|
58
|
+
var n = this.root;
|
|
59
|
+
var n_stack = [];
|
|
60
|
+
var d_stack = [];
|
|
61
|
+
let d = 0;
|
|
62
|
+
while (n) {
|
|
63
|
+
d = cmp(key, n.key);
|
|
64
|
+
n_stack.push(n);
|
|
65
|
+
d_stack.push(d);
|
|
66
|
+
// If the keys are equivalent, skip straight to the replace = true case.
|
|
67
|
+
if (d === 0) break;
|
|
68
|
+
else if (d < 0) {
|
|
69
|
+
n = n.left;
|
|
70
|
+
} else {
|
|
71
|
+
n = n.right;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const replace = d === 0 && n_stack.length > 0;
|
|
76
|
+
if (replace) {
|
|
77
|
+
// The last node in the n_stack has key equivalent to `key`.
|
|
78
|
+
// Replace its entry without changing the tree structure.
|
|
79
|
+
const lastN = n_stack[n_stack.length - 1];
|
|
80
|
+
if (lastN.key === key && lastN.value === value) return this;
|
|
81
|
+
n_stack[n_stack.length - 1] = new RBNode(
|
|
82
|
+
lastN._color,
|
|
83
|
+
key,
|
|
84
|
+
value,
|
|
85
|
+
lastN.left,
|
|
86
|
+
lastN.right
|
|
87
|
+
);
|
|
88
|
+
} else {
|
|
89
|
+
n_stack.push(new RBNode(RED, key, value, null, null));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//Rebuild path to leaf node
|
|
93
|
+
for (var s = n_stack.length - 2; s >= 0; --s) {
|
|
94
|
+
var n = n_stack[s];
|
|
95
|
+
if (d_stack[s] <= 0) {
|
|
96
|
+
n_stack[s] = new RBNode(
|
|
97
|
+
n._color,
|
|
98
|
+
n.key,
|
|
99
|
+
n.value,
|
|
100
|
+
n_stack[s + 1],
|
|
101
|
+
n.right
|
|
102
|
+
);
|
|
103
|
+
} else {
|
|
104
|
+
n_stack[s] = new RBNode(n._color, n.key, n.value, n.left, n_stack[s + 1]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (replace) return new RedBlackTree(cmp, n_stack[0]);
|
|
109
|
+
|
|
110
|
+
//Rebalance tree using rotations
|
|
111
|
+
//console.log("start insert", key, d_stack)
|
|
112
|
+
for (var s = n_stack.length - 1; s > 1; --s) {
|
|
113
|
+
var p = n_stack[s - 1];
|
|
114
|
+
var n = n_stack[s];
|
|
115
|
+
if (p._color === BLACK || n._color === BLACK) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
var pp = n_stack[s - 2];
|
|
119
|
+
if (pp.left === p) {
|
|
120
|
+
if (p.left === n) {
|
|
121
|
+
var y = pp.right;
|
|
122
|
+
if (y && y._color === RED) {
|
|
123
|
+
//console.log("LLr")
|
|
124
|
+
p._color = BLACK;
|
|
125
|
+
pp.right = repaint(BLACK, y);
|
|
126
|
+
pp._color = RED;
|
|
127
|
+
s -= 1;
|
|
128
|
+
} else {
|
|
129
|
+
//console.log("LLb")
|
|
130
|
+
pp._color = RED;
|
|
131
|
+
pp.left = p.right;
|
|
132
|
+
p._color = BLACK;
|
|
133
|
+
p.right = pp;
|
|
134
|
+
n_stack[s - 2] = p;
|
|
135
|
+
n_stack[s - 1] = n;
|
|
136
|
+
if (s >= 3) {
|
|
137
|
+
var ppp = n_stack[s - 3];
|
|
138
|
+
if (ppp.left === pp) {
|
|
139
|
+
ppp.left = p;
|
|
140
|
+
} else {
|
|
141
|
+
ppp.right = p;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
var y = pp.right;
|
|
148
|
+
if (y && y._color === RED) {
|
|
149
|
+
//console.log("LRr")
|
|
150
|
+
p._color = BLACK;
|
|
151
|
+
pp.right = repaint(BLACK, y);
|
|
152
|
+
pp._color = RED;
|
|
153
|
+
s -= 1;
|
|
154
|
+
} else {
|
|
155
|
+
//console.log("LRb")
|
|
156
|
+
p.right = n.left;
|
|
157
|
+
pp._color = RED;
|
|
158
|
+
pp.left = n.right;
|
|
159
|
+
n._color = BLACK;
|
|
160
|
+
n.left = p;
|
|
161
|
+
n.right = pp;
|
|
162
|
+
n_stack[s - 2] = n;
|
|
163
|
+
n_stack[s - 1] = p;
|
|
164
|
+
if (s >= 3) {
|
|
165
|
+
var ppp = n_stack[s - 3];
|
|
166
|
+
if (ppp.left === pp) {
|
|
167
|
+
ppp.left = n;
|
|
168
|
+
} else {
|
|
169
|
+
ppp.right = n;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
if (p.right === n) {
|
|
177
|
+
var y = pp.left;
|
|
178
|
+
if (y && y._color === RED) {
|
|
179
|
+
//console.log("RRr", y.key)
|
|
180
|
+
p._color = BLACK;
|
|
181
|
+
pp.left = repaint(BLACK, y);
|
|
182
|
+
pp._color = RED;
|
|
183
|
+
s -= 1;
|
|
184
|
+
} else {
|
|
185
|
+
//console.log("RRb")
|
|
186
|
+
pp._color = RED;
|
|
187
|
+
pp.right = p.left;
|
|
188
|
+
p._color = BLACK;
|
|
189
|
+
p.left = pp;
|
|
190
|
+
n_stack[s - 2] = p;
|
|
191
|
+
n_stack[s - 1] = n;
|
|
192
|
+
if (s >= 3) {
|
|
193
|
+
var ppp = n_stack[s - 3];
|
|
194
|
+
if (ppp.right === pp) {
|
|
195
|
+
ppp.right = p;
|
|
196
|
+
} else {
|
|
197
|
+
ppp.left = p;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
var y = pp.left;
|
|
204
|
+
if (y && y._color === RED) {
|
|
205
|
+
//console.log("RLr")
|
|
206
|
+
p._color = BLACK;
|
|
207
|
+
pp.left = repaint(BLACK, y);
|
|
208
|
+
pp._color = RED;
|
|
209
|
+
s -= 1;
|
|
210
|
+
} else {
|
|
211
|
+
//console.log("RLb")
|
|
212
|
+
p.left = n.right;
|
|
213
|
+
pp._color = RED;
|
|
214
|
+
pp.right = n.left;
|
|
215
|
+
n._color = BLACK;
|
|
216
|
+
n.right = p;
|
|
217
|
+
n.left = pp;
|
|
218
|
+
n_stack[s - 2] = n;
|
|
219
|
+
n_stack[s - 1] = p;
|
|
220
|
+
if (s >= 3) {
|
|
221
|
+
var ppp = n_stack[s - 3];
|
|
222
|
+
if (ppp.right === pp) {
|
|
223
|
+
ppp.right = n;
|
|
224
|
+
} else {
|
|
225
|
+
ppp.left = n;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
//Return new tree
|
|
234
|
+
n_stack[0]._color = BLACK;
|
|
235
|
+
return new RedBlackTree(cmp, n_stack[0]);
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// //Visit all nodes inorder
|
|
239
|
+
// function doVisitFull(visit, node) {
|
|
240
|
+
// if (node.left) {
|
|
241
|
+
// var v = doVisitFull(visit, node.left);
|
|
242
|
+
// if (v) {
|
|
243
|
+
// return v;
|
|
244
|
+
// }
|
|
245
|
+
// }
|
|
246
|
+
// var v = visit(node.key, node.value);
|
|
247
|
+
// if (v) {
|
|
248
|
+
// return v;
|
|
249
|
+
// }
|
|
250
|
+
// if (node.right) {
|
|
251
|
+
// return doVisitFull(visit, node.right);
|
|
252
|
+
// }
|
|
253
|
+
// }
|
|
254
|
+
|
|
255
|
+
// //Visit half nodes in order
|
|
256
|
+
// function doVisitHalf(lo, compare, visit, node) {
|
|
257
|
+
// var l = compare(lo, node.key);
|
|
258
|
+
// if (l <= 0) {
|
|
259
|
+
// if (node.left) {
|
|
260
|
+
// var v = doVisitHalf(lo, compare, visit, node.left);
|
|
261
|
+
// if (v) {
|
|
262
|
+
// return v;
|
|
263
|
+
// }
|
|
264
|
+
// }
|
|
265
|
+
// var v = visit(node.key, node.value);
|
|
266
|
+
// if (v) {
|
|
267
|
+
// return v;
|
|
268
|
+
// }
|
|
269
|
+
// }
|
|
270
|
+
// if (node.right) {
|
|
271
|
+
// return doVisitHalf(lo, compare, visit, node.right);
|
|
272
|
+
// }
|
|
273
|
+
// }
|
|
274
|
+
|
|
275
|
+
// //Visit all nodes within a range
|
|
276
|
+
// function doVisit(lo, hi, compare, visit, node) {
|
|
277
|
+
// var l = compare(lo, node.key);
|
|
278
|
+
// var h = compare(hi, node.key);
|
|
279
|
+
// var v;
|
|
280
|
+
// if (l <= 0) {
|
|
281
|
+
// if (node.left) {
|
|
282
|
+
// v = doVisit(lo, hi, compare, visit, node.left);
|
|
283
|
+
// if (v) {
|
|
284
|
+
// return v;
|
|
285
|
+
// }
|
|
286
|
+
// }
|
|
287
|
+
// if (h > 0) {
|
|
288
|
+
// v = visit(node.key, node.value);
|
|
289
|
+
// if (v) {
|
|
290
|
+
// return v;
|
|
291
|
+
// }
|
|
292
|
+
// }
|
|
293
|
+
// }
|
|
294
|
+
// if (h > 0 && node.right) {
|
|
295
|
+
// return doVisit(lo, hi, compare, visit, node.right);
|
|
296
|
+
// }
|
|
297
|
+
// }
|
|
298
|
+
|
|
299
|
+
// proto.forEach = function rbTreeForEach(visit, lo, hi) {
|
|
300
|
+
// if (!this.root) {
|
|
301
|
+
// return;
|
|
302
|
+
// }
|
|
303
|
+
// switch (arguments.length) {
|
|
304
|
+
// case 1:
|
|
305
|
+
// return doVisitFull(visit, this.root);
|
|
306
|
+
// break;
|
|
307
|
+
|
|
308
|
+
// case 2:
|
|
309
|
+
// return doVisitHalf(lo, this._compare, visit, this.root);
|
|
310
|
+
// break;
|
|
311
|
+
|
|
312
|
+
// case 3:
|
|
313
|
+
// if (this._compare(lo, hi) >= 0) {
|
|
314
|
+
// return;
|
|
315
|
+
// }
|
|
316
|
+
// return doVisit(lo, hi, this._compare, visit, this.root);
|
|
317
|
+
// break;
|
|
318
|
+
// }
|
|
319
|
+
// };
|
|
320
|
+
|
|
321
|
+
// //First item in list
|
|
322
|
+
// Object.defineProperty(proto, "begin", {
|
|
323
|
+
// get: function () {
|
|
324
|
+
// var stack = [];
|
|
325
|
+
// var n = this.root;
|
|
326
|
+
// while (n) {
|
|
327
|
+
// stack.push(n);
|
|
328
|
+
// n = n.left;
|
|
329
|
+
// }
|
|
330
|
+
// return new RedBlackTreeIterator(this, stack);
|
|
331
|
+
// },
|
|
332
|
+
// });
|
|
333
|
+
|
|
334
|
+
// //Last item in list
|
|
335
|
+
// Object.defineProperty(proto, "end", {
|
|
336
|
+
// get: function () {
|
|
337
|
+
// var stack = [];
|
|
338
|
+
// var n = this.root;
|
|
339
|
+
// while (n) {
|
|
340
|
+
// stack.push(n);
|
|
341
|
+
// n = n.right;
|
|
342
|
+
// }
|
|
343
|
+
// return new RedBlackTreeIterator(this, stack);
|
|
344
|
+
// },
|
|
345
|
+
// });
|
|
346
|
+
|
|
347
|
+
// proto.ge = function (key) {
|
|
348
|
+
// var cmp = this._compare;
|
|
349
|
+
// var n = this.root;
|
|
350
|
+
// var stack = [];
|
|
351
|
+
// var last_ptr = 0;
|
|
352
|
+
// while (n) {
|
|
353
|
+
// var d = cmp(key, n.key);
|
|
354
|
+
// stack.push(n);
|
|
355
|
+
// if (d <= 0) {
|
|
356
|
+
// last_ptr = stack.length;
|
|
357
|
+
// }
|
|
358
|
+
// if (d <= 0) {
|
|
359
|
+
// n = n.left;
|
|
360
|
+
// } else {
|
|
361
|
+
// n = n.right;
|
|
362
|
+
// }
|
|
363
|
+
// }
|
|
364
|
+
// stack.length = last_ptr;
|
|
365
|
+
// return new RedBlackTreeIterator(this, stack);
|
|
366
|
+
// };
|
|
367
|
+
|
|
368
|
+
// proto.gt = function (key) {
|
|
369
|
+
// var cmp = this._compare;
|
|
370
|
+
// var n = this.root;
|
|
371
|
+
// var stack = [];
|
|
372
|
+
// var last_ptr = 0;
|
|
373
|
+
// while (n) {
|
|
374
|
+
// var d = cmp(key, n.key);
|
|
375
|
+
// stack.push(n);
|
|
376
|
+
// if (d < 0) {
|
|
377
|
+
// last_ptr = stack.length;
|
|
378
|
+
// }
|
|
379
|
+
// if (d < 0) {
|
|
380
|
+
// n = n.left;
|
|
381
|
+
// } else {
|
|
382
|
+
// n = n.right;
|
|
383
|
+
// }
|
|
384
|
+
// }
|
|
385
|
+
// stack.length = last_ptr;
|
|
386
|
+
// return new RedBlackTreeIterator(this, stack);
|
|
387
|
+
// };
|
|
388
|
+
|
|
389
|
+
// proto.lt = function (key) {
|
|
390
|
+
// var cmp = this._compare;
|
|
391
|
+
// var n = this.root;
|
|
392
|
+
// var stack = [];
|
|
393
|
+
// var last_ptr = 0;
|
|
394
|
+
// while (n) {
|
|
395
|
+
// var d = cmp(key, n.key);
|
|
396
|
+
// stack.push(n);
|
|
397
|
+
// if (d > 0) {
|
|
398
|
+
// last_ptr = stack.length;
|
|
399
|
+
// }
|
|
400
|
+
// if (d <= 0) {
|
|
401
|
+
// n = n.left;
|
|
402
|
+
// } else {
|
|
403
|
+
// n = n.right;
|
|
404
|
+
// }
|
|
405
|
+
// }
|
|
406
|
+
// stack.length = last_ptr;
|
|
407
|
+
// return new RedBlackTreeIterator(this, stack);
|
|
408
|
+
// };
|
|
409
|
+
|
|
410
|
+
proto.le = function (key) {
|
|
411
|
+
var cmp = this._compare;
|
|
412
|
+
var n = this.root;
|
|
413
|
+
var stack = [];
|
|
414
|
+
var last_ptr = 0;
|
|
415
|
+
while (n) {
|
|
416
|
+
var d = cmp(key, n.key);
|
|
417
|
+
stack.push(n);
|
|
418
|
+
if (d >= 0) {
|
|
419
|
+
last_ptr = stack.length;
|
|
420
|
+
}
|
|
421
|
+
if (d < 0) {
|
|
422
|
+
n = n.left;
|
|
423
|
+
} else {
|
|
424
|
+
n = n.right;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
stack.length = last_ptr;
|
|
428
|
+
return new RedBlackTreeIterator(this, stack);
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
//Finds the item with key if it exists
|
|
432
|
+
proto.find = function (key) {
|
|
433
|
+
var cmp = this._compare;
|
|
434
|
+
var n = this.root;
|
|
435
|
+
var stack = [];
|
|
436
|
+
while (n) {
|
|
437
|
+
var d = cmp(key, n.key);
|
|
438
|
+
stack.push(n);
|
|
439
|
+
if (d === 0) {
|
|
440
|
+
return new RedBlackTreeIterator(this, stack);
|
|
441
|
+
}
|
|
442
|
+
if (d <= 0) {
|
|
443
|
+
n = n.left;
|
|
444
|
+
} else {
|
|
445
|
+
n = n.right;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return new RedBlackTreeIterator(this, []);
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
//Removes item with key from tree
|
|
452
|
+
proto.remove = function (key) {
|
|
453
|
+
var iter = this.find(key);
|
|
454
|
+
return iter.remove();
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
//Returns the item at `key`
|
|
458
|
+
proto.get = function (key) {
|
|
459
|
+
var cmp = this._compare;
|
|
460
|
+
var n = this.root;
|
|
461
|
+
while (n) {
|
|
462
|
+
var d = cmp(key, n.key);
|
|
463
|
+
if (d === 0) {
|
|
464
|
+
return n.value;
|
|
465
|
+
}
|
|
466
|
+
if (d <= 0) {
|
|
467
|
+
n = n.left;
|
|
468
|
+
} else {
|
|
469
|
+
n = n.right;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return;
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
//Iterator for red black tree
|
|
476
|
+
function RedBlackTreeIterator(tree, stack) {
|
|
477
|
+
this.tree = tree;
|
|
478
|
+
this._stack = stack;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
var iproto = RedBlackTreeIterator.prototype;
|
|
482
|
+
|
|
483
|
+
// //Test if iterator is valid
|
|
484
|
+
// Object.defineProperty(iproto, "valid", {
|
|
485
|
+
// get: function () {
|
|
486
|
+
// return this._stack.length > 0;
|
|
487
|
+
// },
|
|
488
|
+
// });
|
|
489
|
+
|
|
490
|
+
// //Node of the iterator
|
|
491
|
+
// Object.defineProperty(iproto, "node", {
|
|
492
|
+
// get: function () {
|
|
493
|
+
// if (this._stack.length > 0) {
|
|
494
|
+
// return this._stack[this._stack.length - 1];
|
|
495
|
+
// }
|
|
496
|
+
// return null;
|
|
497
|
+
// },
|
|
498
|
+
// enumerable: true,
|
|
499
|
+
// });
|
|
500
|
+
|
|
501
|
+
// //Makes a copy of an iterator
|
|
502
|
+
// iproto.clone = function () {
|
|
503
|
+
// return new RedBlackTreeIterator(this.tree, this._stack.slice());
|
|
504
|
+
// };
|
|
505
|
+
|
|
506
|
+
//Swaps two nodes
|
|
507
|
+
function swapNode(n, v) {
|
|
508
|
+
n.key = v.key;
|
|
509
|
+
n.value = v.value;
|
|
510
|
+
n.left = v.left;
|
|
511
|
+
n.right = v.right;
|
|
512
|
+
n._color = v._color;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
//Fix up a double black node in a tree
|
|
516
|
+
function fixDoubleBlack(stack) {
|
|
517
|
+
var n, p, s, z;
|
|
518
|
+
for (var i = stack.length - 1; i >= 0; --i) {
|
|
519
|
+
n = stack[i];
|
|
520
|
+
if (i === 0) {
|
|
521
|
+
n._color = BLACK;
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
//console.log("visit node:", n.key, i, stack[i].key, stack[i-1].key)
|
|
525
|
+
p = stack[i - 1];
|
|
526
|
+
if (p.left === n) {
|
|
527
|
+
//console.log("left child")
|
|
528
|
+
s = p.right;
|
|
529
|
+
if (s.right && s.right._color === RED) {
|
|
530
|
+
//console.log("case 1: right sibling child red")
|
|
531
|
+
s = p.right = cloneNode(s);
|
|
532
|
+
z = s.right = cloneNode(s.right);
|
|
533
|
+
p.right = s.left;
|
|
534
|
+
s.left = p;
|
|
535
|
+
s.right = z;
|
|
536
|
+
s._color = p._color;
|
|
537
|
+
n._color = BLACK;
|
|
538
|
+
p._color = BLACK;
|
|
539
|
+
z._color = BLACK;
|
|
540
|
+
if (i > 1) {
|
|
541
|
+
var pp = stack[i - 2];
|
|
542
|
+
if (pp.left === p) {
|
|
543
|
+
pp.left = s;
|
|
544
|
+
} else {
|
|
545
|
+
pp.right = s;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
stack[i - 1] = s;
|
|
549
|
+
return;
|
|
550
|
+
} else if (s.left && s.left._color === RED) {
|
|
551
|
+
//console.log("case 1: left sibling child red")
|
|
552
|
+
s = p.right = cloneNode(s);
|
|
553
|
+
z = s.left = cloneNode(s.left);
|
|
554
|
+
p.right = z.left;
|
|
555
|
+
s.left = z.right;
|
|
556
|
+
z.left = p;
|
|
557
|
+
z.right = s;
|
|
558
|
+
z._color = p._color;
|
|
559
|
+
p._color = BLACK;
|
|
560
|
+
s._color = BLACK;
|
|
561
|
+
n._color = BLACK;
|
|
562
|
+
if (i > 1) {
|
|
563
|
+
var pp = stack[i - 2];
|
|
564
|
+
if (pp.left === p) {
|
|
565
|
+
pp.left = z;
|
|
566
|
+
} else {
|
|
567
|
+
pp.right = z;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
stack[i - 1] = z;
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
if (s._color === BLACK) {
|
|
574
|
+
if (p._color === RED) {
|
|
575
|
+
//console.log("case 2: black sibling, red parent", p.right.value)
|
|
576
|
+
p._color = BLACK;
|
|
577
|
+
p.right = repaint(RED, s);
|
|
578
|
+
return;
|
|
579
|
+
} else {
|
|
580
|
+
//console.log("case 2: black sibling, black parent", p.right.value)
|
|
581
|
+
p.right = repaint(RED, s);
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
} else {
|
|
585
|
+
//console.log("case 3: red sibling")
|
|
586
|
+
s = cloneNode(s);
|
|
587
|
+
p.right = s.left;
|
|
588
|
+
s.left = p;
|
|
589
|
+
s._color = p._color;
|
|
590
|
+
p._color = RED;
|
|
591
|
+
if (i > 1) {
|
|
592
|
+
var pp = stack[i - 2];
|
|
593
|
+
if (pp.left === p) {
|
|
594
|
+
pp.left = s;
|
|
595
|
+
} else {
|
|
596
|
+
pp.right = s;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
stack[i - 1] = s;
|
|
600
|
+
stack[i] = p;
|
|
601
|
+
if (i + 1 < stack.length) {
|
|
602
|
+
stack[i + 1] = n;
|
|
603
|
+
} else {
|
|
604
|
+
stack.push(n);
|
|
605
|
+
}
|
|
606
|
+
i = i + 2;
|
|
607
|
+
}
|
|
608
|
+
} else {
|
|
609
|
+
//console.log("right child")
|
|
610
|
+
s = p.left;
|
|
611
|
+
if (s.left && s.left._color === RED) {
|
|
612
|
+
//console.log("case 1: left sibling child red", p.value, p._color)
|
|
613
|
+
s = p.left = cloneNode(s);
|
|
614
|
+
z = s.left = cloneNode(s.left);
|
|
615
|
+
p.left = s.right;
|
|
616
|
+
s.right = p;
|
|
617
|
+
s.left = z;
|
|
618
|
+
s._color = p._color;
|
|
619
|
+
n._color = BLACK;
|
|
620
|
+
p._color = BLACK;
|
|
621
|
+
z._color = BLACK;
|
|
622
|
+
if (i > 1) {
|
|
623
|
+
var pp = stack[i - 2];
|
|
624
|
+
if (pp.right === p) {
|
|
625
|
+
pp.right = s;
|
|
626
|
+
} else {
|
|
627
|
+
pp.left = s;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
stack[i - 1] = s;
|
|
631
|
+
return;
|
|
632
|
+
} else if (s.right && s.right._color === RED) {
|
|
633
|
+
//console.log("case 1: right sibling child red")
|
|
634
|
+
s = p.left = cloneNode(s);
|
|
635
|
+
z = s.right = cloneNode(s.right);
|
|
636
|
+
p.left = z.right;
|
|
637
|
+
s.right = z.left;
|
|
638
|
+
z.right = p;
|
|
639
|
+
z.left = s;
|
|
640
|
+
z._color = p._color;
|
|
641
|
+
p._color = BLACK;
|
|
642
|
+
s._color = BLACK;
|
|
643
|
+
n._color = BLACK;
|
|
644
|
+
if (i > 1) {
|
|
645
|
+
var pp = stack[i - 2];
|
|
646
|
+
if (pp.right === p) {
|
|
647
|
+
pp.right = z;
|
|
648
|
+
} else {
|
|
649
|
+
pp.left = z;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
stack[i - 1] = z;
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
if (s._color === BLACK) {
|
|
656
|
+
if (p._color === RED) {
|
|
657
|
+
//console.log("case 2: black sibling, red parent")
|
|
658
|
+
p._color = BLACK;
|
|
659
|
+
p.left = repaint(RED, s);
|
|
660
|
+
return;
|
|
661
|
+
} else {
|
|
662
|
+
//console.log("case 2: black sibling, black parent")
|
|
663
|
+
p.left = repaint(RED, s);
|
|
664
|
+
continue;
|
|
665
|
+
}
|
|
666
|
+
} else {
|
|
667
|
+
//console.log("case 3: red sibling")
|
|
668
|
+
s = cloneNode(s);
|
|
669
|
+
p.left = s.right;
|
|
670
|
+
s.right = p;
|
|
671
|
+
s._color = p._color;
|
|
672
|
+
p._color = RED;
|
|
673
|
+
if (i > 1) {
|
|
674
|
+
var pp = stack[i - 2];
|
|
675
|
+
if (pp.right === p) {
|
|
676
|
+
pp.right = s;
|
|
677
|
+
} else {
|
|
678
|
+
pp.left = s;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
stack[i - 1] = s;
|
|
682
|
+
stack[i] = p;
|
|
683
|
+
if (i + 1 < stack.length) {
|
|
684
|
+
stack[i + 1] = n;
|
|
685
|
+
} else {
|
|
686
|
+
stack.push(n);
|
|
687
|
+
}
|
|
688
|
+
i = i + 2;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
//Removes item at iterator from tree
|
|
695
|
+
iproto.remove = function () {
|
|
696
|
+
var stack = this._stack;
|
|
697
|
+
if (stack.length === 0) {
|
|
698
|
+
return this.tree;
|
|
699
|
+
}
|
|
700
|
+
//First copy path to node
|
|
701
|
+
var cstack = new Array(stack.length);
|
|
702
|
+
var n = stack[stack.length - 1];
|
|
703
|
+
cstack[cstack.length - 1] = new RBNode(
|
|
704
|
+
n._color,
|
|
705
|
+
n.key,
|
|
706
|
+
n.value,
|
|
707
|
+
n.left,
|
|
708
|
+
n.right
|
|
709
|
+
);
|
|
710
|
+
for (var i = stack.length - 2; i >= 0; --i) {
|
|
711
|
+
var n = stack[i];
|
|
712
|
+
if (n.left === stack[i + 1]) {
|
|
713
|
+
cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i + 1], n.right);
|
|
714
|
+
} else {
|
|
715
|
+
cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i + 1]);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
//Get node
|
|
720
|
+
n = cstack[cstack.length - 1];
|
|
721
|
+
//console.log("start remove: ", n.value)
|
|
722
|
+
|
|
723
|
+
//If not leaf, then swap with previous node
|
|
724
|
+
if (n.left && n.right) {
|
|
725
|
+
//console.log("moving to leaf")
|
|
726
|
+
|
|
727
|
+
//First walk to previous leaf
|
|
728
|
+
var split = cstack.length;
|
|
729
|
+
n = n.left;
|
|
730
|
+
while (n.right) {
|
|
731
|
+
cstack.push(n);
|
|
732
|
+
n = n.right;
|
|
733
|
+
}
|
|
734
|
+
//Copy path to leaf
|
|
735
|
+
var v = cstack[split - 1];
|
|
736
|
+
cstack.push(new RBNode(n._color, v.key, v.value, n.left, n.right));
|
|
737
|
+
cstack[split - 1].key = n.key;
|
|
738
|
+
cstack[split - 1].value = n.value;
|
|
739
|
+
|
|
740
|
+
//Fix up stack
|
|
741
|
+
for (var i = cstack.length - 2; i >= split; --i) {
|
|
742
|
+
n = cstack[i];
|
|
743
|
+
cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i + 1]);
|
|
744
|
+
}
|
|
745
|
+
cstack[split - 1].left = cstack[split];
|
|
746
|
+
}
|
|
747
|
+
//console.log("stack=", cstack.map(function(v) { return v.value }))
|
|
748
|
+
|
|
749
|
+
//Remove leaf node
|
|
750
|
+
n = cstack[cstack.length - 1];
|
|
751
|
+
if (n._color === RED) {
|
|
752
|
+
//Easy case: removing red leaf
|
|
753
|
+
//console.log("RED leaf")
|
|
754
|
+
var p = cstack[cstack.length - 2];
|
|
755
|
+
if (p.left === n) {
|
|
756
|
+
p.left = null;
|
|
757
|
+
} else if (p.right === n) {
|
|
758
|
+
p.right = null;
|
|
759
|
+
}
|
|
760
|
+
cstack.pop();
|
|
761
|
+
return new RedBlackTree(this.tree._compare, cstack[0]);
|
|
762
|
+
} else {
|
|
763
|
+
if (n.left || n.right) {
|
|
764
|
+
//Second easy case: Single child black parent
|
|
765
|
+
//console.log("BLACK single child")
|
|
766
|
+
if (n.left) {
|
|
767
|
+
swapNode(n, n.left);
|
|
768
|
+
} else if (n.right) {
|
|
769
|
+
swapNode(n, n.right);
|
|
770
|
+
}
|
|
771
|
+
//Child must be red, so repaint it black to balance color
|
|
772
|
+
n._color = BLACK;
|
|
773
|
+
return new RedBlackTree(this.tree._compare, cstack[0]);
|
|
774
|
+
} else if (cstack.length === 1) {
|
|
775
|
+
//Third easy case: root
|
|
776
|
+
//console.log("ROOT")
|
|
777
|
+
return new RedBlackTree(this.tree._compare, null);
|
|
778
|
+
} else {
|
|
779
|
+
//Hard case: Repaint n, and then do some nasty stuff
|
|
780
|
+
//console.log("BLACK leaf no children")
|
|
781
|
+
var parent = cstack[cstack.length - 2];
|
|
782
|
+
fixDoubleBlack(cstack);
|
|
783
|
+
//Fix up links
|
|
784
|
+
if (parent.left === n) {
|
|
785
|
+
parent.left = null;
|
|
786
|
+
} else {
|
|
787
|
+
parent.right = null;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
return new RedBlackTree(this.tree._compare, cstack[0]);
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
//Returns key
|
|
795
|
+
Object.defineProperty(iproto, "key", {
|
|
796
|
+
get: function () {
|
|
797
|
+
if (this._stack.length > 0) {
|
|
798
|
+
return this._stack[this._stack.length - 1].key;
|
|
799
|
+
}
|
|
800
|
+
return;
|
|
801
|
+
},
|
|
802
|
+
enumerable: true,
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
//Returns value
|
|
806
|
+
Object.defineProperty(iproto, "value", {
|
|
807
|
+
get: function () {
|
|
808
|
+
if (this._stack.length > 0) {
|
|
809
|
+
return this._stack[this._stack.length - 1].value;
|
|
810
|
+
}
|
|
811
|
+
return;
|
|
812
|
+
},
|
|
813
|
+
enumerable: true,
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
// //Advances iterator to next element in list
|
|
817
|
+
// iproto.next = function () {
|
|
818
|
+
// var stack = this._stack;
|
|
819
|
+
// if (stack.length === 0) {
|
|
820
|
+
// return;
|
|
821
|
+
// }
|
|
822
|
+
// var n = stack[stack.length - 1];
|
|
823
|
+
// if (n.right) {
|
|
824
|
+
// n = n.right;
|
|
825
|
+
// while (n) {
|
|
826
|
+
// stack.push(n);
|
|
827
|
+
// n = n.left;
|
|
828
|
+
// }
|
|
829
|
+
// } else {
|
|
830
|
+
// stack.pop();
|
|
831
|
+
// while (stack.length > 0 && stack[stack.length - 1].right === n) {
|
|
832
|
+
// n = stack[stack.length - 1];
|
|
833
|
+
// stack.pop();
|
|
834
|
+
// }
|
|
835
|
+
// }
|
|
836
|
+
// };
|
|
837
|
+
|
|
838
|
+
// //Checks if iterator is at end of tree
|
|
839
|
+
// Object.defineProperty(iproto, "hasNext", {
|
|
840
|
+
// get: function () {
|
|
841
|
+
// var stack = this._stack;
|
|
842
|
+
// if (stack.length === 0) {
|
|
843
|
+
// return false;
|
|
844
|
+
// }
|
|
845
|
+
// if (stack[stack.length - 1].right) {
|
|
846
|
+
// return true;
|
|
847
|
+
// }
|
|
848
|
+
// for (var s = stack.length - 1; s > 0; --s) {
|
|
849
|
+
// if (stack[s - 1].left === stack[s]) {
|
|
850
|
+
// return true;
|
|
851
|
+
// }
|
|
852
|
+
// }
|
|
853
|
+
// return false;
|
|
854
|
+
// },
|
|
855
|
+
// });
|
|
856
|
+
|
|
857
|
+
// //Update value
|
|
858
|
+
// iproto.update = function (value) {
|
|
859
|
+
// var stack = this._stack;
|
|
860
|
+
// if (stack.length === 0) {
|
|
861
|
+
// throw new Error("Can't update empty node!");
|
|
862
|
+
// }
|
|
863
|
+
// var cstack = new Array(stack.length);
|
|
864
|
+
// var n = stack[stack.length - 1];
|
|
865
|
+
// cstack[cstack.length - 1] = new RBNode(
|
|
866
|
+
// n._color,
|
|
867
|
+
// n.key,
|
|
868
|
+
// value,
|
|
869
|
+
// n.left,
|
|
870
|
+
// n.right
|
|
871
|
+
// );
|
|
872
|
+
// for (var i = stack.length - 2; i >= 0; --i) {
|
|
873
|
+
// n = stack[i];
|
|
874
|
+
// if (n.left === stack[i + 1]) {
|
|
875
|
+
// cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i + 1], n.right);
|
|
876
|
+
// } else {
|
|
877
|
+
// cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i + 1]);
|
|
878
|
+
// }
|
|
879
|
+
// }
|
|
880
|
+
// return new RedBlackTree(this.tree._compare, cstack[0]);
|
|
881
|
+
// };
|
|
882
|
+
|
|
883
|
+
// //Moves iterator backward one element
|
|
884
|
+
// iproto.prev = function () {
|
|
885
|
+
// var stack = this._stack;
|
|
886
|
+
// if (stack.length === 0) {
|
|
887
|
+
// return;
|
|
888
|
+
// }
|
|
889
|
+
// var n = stack[stack.length - 1];
|
|
890
|
+
// if (n.left) {
|
|
891
|
+
// n = n.left;
|
|
892
|
+
// while (n) {
|
|
893
|
+
// stack.push(n);
|
|
894
|
+
// n = n.right;
|
|
895
|
+
// }
|
|
896
|
+
// } else {
|
|
897
|
+
// stack.pop();
|
|
898
|
+
// while (stack.length > 0 && stack[stack.length - 1].left === n) {
|
|
899
|
+
// n = stack[stack.length - 1];
|
|
900
|
+
// stack.pop();
|
|
901
|
+
// }
|
|
902
|
+
// }
|
|
903
|
+
// };
|
|
904
|
+
|
|
905
|
+
// //Checks if iterator is at start of tree
|
|
906
|
+
// Object.defineProperty(iproto, "hasPrev", {
|
|
907
|
+
// get: function () {
|
|
908
|
+
// var stack = this._stack;
|
|
909
|
+
// if (stack.length === 0) {
|
|
910
|
+
// return false;
|
|
911
|
+
// }
|
|
912
|
+
// if (stack[stack.length - 1].left) {
|
|
913
|
+
// return true;
|
|
914
|
+
// }
|
|
915
|
+
// for (var s = stack.length - 1; s > 0; --s) {
|
|
916
|
+
// if (stack[s - 1].right === stack[s]) {
|
|
917
|
+
// return true;
|
|
918
|
+
// }
|
|
919
|
+
// }
|
|
920
|
+
// return false;
|
|
921
|
+
// },
|
|
922
|
+
// });
|
|
923
|
+
|
|
924
|
+
// //Default comparison function
|
|
925
|
+
// function defaultCompare(a, b) {
|
|
926
|
+
// if (a < b) {
|
|
927
|
+
// return -1;
|
|
928
|
+
// }
|
|
929
|
+
// if (a > b) {
|
|
930
|
+
// return 1;
|
|
931
|
+
// }
|
|
932
|
+
// return 0;
|
|
933
|
+
// }
|
|
934
|
+
|
|
935
|
+
//Build a tree
|
|
936
|
+
function createRBTree(compare) {
|
|
937
|
+
return new RedBlackTree(compare, null);
|
|
938
|
+
}
|