3 module.exports = createRBTree
8 function RBNode(color, key, value, left, right, count) {
17 function cloneNode(node) {
18 return new RBNode(node._color, node.key, node.value, node.left, node.right, node._count)
21 function repaint(color, node) {
22 return new RBNode(color, node.key, node.value, node.left, node.right, node._count)
25 function recount(node) {
26 node._count = 1 + (node.left ? node.left._count : 0) + (node.right ? node.right._count : 0)
29 function RedBlackTree(compare, root) {
30 this._compare = compare
34 var proto = RedBlackTree.prototype
36 Object.defineProperty(proto, "keys", {
39 this.forEach(function(k,v) {
46 Object.defineProperty(proto, "values", {
49 this.forEach(function(k,v) {
56 //Returns the number of nodes in the tree
57 Object.defineProperty(proto, "length", {
60 return this.root._count
66 //Insert a new item into the tree
67 proto.insert = function(key, value) {
68 var cmp = this._compare
69 //Find point to insert new node at
74 var d = cmp(key, n.key)
83 //Rebuild path to leaf node
84 n_stack.push(new RBNode(RED, key, value, null, null, 1))
85 for(var s=n_stack.length-2; s>=0; --s) {
88 n_stack[s] = new RBNode(n._color, n.key, n.value, n_stack[s+1], n.right, n._count+1)
90 n_stack[s] = new RBNode(n._color, n.key, n.value, n.left, n_stack[s+1], n._count+1)
93 //Rebalance tree using rotations
94 //console.log("start insert", key, d_stack)
95 for(var s=n_stack.length-1; s>1; --s) {
98 if(p._color === BLACK || n._color === BLACK) {
101 var pp = n_stack[s-2]
105 if(y && y._color === RED) {
108 pp.right = repaint(BLACK, y)
122 var ppp = n_stack[s-3]
123 if(ppp.left === pp) {
133 if(y && y._color === RED) {
136 pp.right = repaint(BLACK, y)
153 var ppp = n_stack[s-3]
154 if(ppp.left === pp) {
166 if(y && y._color === RED) {
167 //console.log("RRr", y.key)
169 pp.left = repaint(BLACK, y)
183 var ppp = n_stack[s-3]
184 if(ppp.right === pp) {
194 if(y && y._color === RED) {
197 pp.left = repaint(BLACK, y)
214 var ppp = n_stack[s-3]
215 if(ppp.right === pp) {
227 n_stack[0]._color = BLACK
228 return new RedBlackTree(cmp, n_stack[0])
232 //Visit all nodes inorder
233 function doVisitFull(visit, node) {
235 var v = doVisitFull(visit, node.left)
238 var v = visit(node.key, node.value)
241 return doVisitFull(visit, node.right)
245 //Visit half nodes in order
246 function doVisitHalf(lo, compare, visit, node) {
247 var l = compare(lo, node.key)
250 var v = doVisitHalf(lo, compare, visit, node.left)
253 var v = visit(node.key, node.value)
257 return doVisitHalf(lo, compare, visit, node.right)
261 //Visit all nodes within a range
262 function doVisit(lo, hi, compare, visit, node) {
263 var l = compare(lo, node.key)
264 var h = compare(hi, node.key)
268 v = doVisit(lo, hi, compare, visit, node.left)
272 v = visit(node.key, node.value)
276 if(h > 0 && node.right) {
277 return doVisit(lo, hi, compare, visit, node.right)
282 proto.forEach = function rbTreeForEach(visit, lo, hi) {
286 switch(arguments.length) {
288 return doVisitFull(visit, this.root)
292 return doVisitHalf(lo, this._compare, visit, this.root)
296 if(this._compare(lo, hi) >= 0) {
299 return doVisit(lo, hi, this._compare, visit, this.root)
305 Object.defineProperty(proto, "begin", {
313 return new RedBlackTreeIterator(this, stack)
318 Object.defineProperty(proto, "end", {
326 return new RedBlackTreeIterator(this, stack)
330 //Find the ith item in the tree
331 proto.at = function(idx) {
333 return new RedBlackTreeIterator(this, [])
340 if(idx < n.left._count) {
347 return new RedBlackTreeIterator(this, stack)
351 if(idx >= n.right._count) {
359 return new RedBlackTreeIterator(this, [])
362 proto.ge = function(key) {
363 var cmp = this._compare
368 var d = cmp(key, n.key)
371 last_ptr = stack.length
379 stack.length = last_ptr
380 return new RedBlackTreeIterator(this, stack)
383 proto.gt = function(key) {
384 var cmp = this._compare
389 var d = cmp(key, n.key)
392 last_ptr = stack.length
400 stack.length = last_ptr
401 return new RedBlackTreeIterator(this, stack)
404 proto.lt = function(key) {
405 var cmp = this._compare
410 var d = cmp(key, n.key)
413 last_ptr = stack.length
421 stack.length = last_ptr
422 return new RedBlackTreeIterator(this, stack)
425 proto.le = function(key) {
426 var cmp = this._compare
431 var d = cmp(key, n.key)
434 last_ptr = stack.length
442 stack.length = last_ptr
443 return new RedBlackTreeIterator(this, stack)
446 //Finds the item with key if it exists
447 proto.find = function(key) {
448 var cmp = this._compare
452 var d = cmp(key, n.key)
455 return new RedBlackTreeIterator(this, stack)
463 return new RedBlackTreeIterator(this, [])
466 //Removes item with key from tree
467 proto.remove = function(key) {
468 var iter = this.find(key)
475 //Returns the item at `key`
476 proto.get = function(key) {
477 var cmp = this._compare
480 var d = cmp(key, n.key)
493 //Iterator for red black tree
494 function RedBlackTreeIterator(tree, stack) {
499 var iproto = RedBlackTreeIterator.prototype
501 //Test if iterator is valid
502 Object.defineProperty(iproto, "valid", {
504 return this._stack.length > 0
508 //Node of the iterator
509 Object.defineProperty(iproto, "node", {
511 if(this._stack.length > 0) {
512 return this._stack[this._stack.length-1]
519 //Makes a copy of an iterator
520 iproto.clone = function() {
521 return new RedBlackTreeIterator(this.tree, this._stack.slice())
525 function swapNode(n, v) {
534 //Fix up a double black node in a tree
535 function fixDoubleBlack(stack) {
537 for(var i=stack.length-1; i>=0; --i) {
543 //console.log("visit node:", n.key, i, stack[i].key, stack[i-1].key)
546 //console.log("left child")
548 if(s.right && s.right._color === RED) {
549 //console.log("case 1: right sibling child red")
550 s = p.right = cloneNode(s)
551 z = s.right = cloneNode(s.right)
571 } else if(s.left && s.left._color === RED) {
572 //console.log("case 1: left sibling child red")
573 s = p.right = cloneNode(s)
574 z = s.left = cloneNode(s.left)
597 if(s._color === BLACK) {
598 if(p._color === RED) {
599 //console.log("case 2: black sibling, red parent", p.right.value)
601 p.right = repaint(RED, s)
604 //console.log("case 2: black sibling, black parent", p.right.value)
605 p.right = repaint(RED, s)
609 //console.log("case 3: red sibling")
627 if(i+1 < stack.length) {
635 //console.log("right child")
637 if(s.left && s.left._color === RED) {
638 //console.log("case 1: left sibling child red", p.value, p._color)
639 s = p.left = cloneNode(s)
640 z = s.left = cloneNode(s.left)
660 } else if(s.right && s.right._color === RED) {
661 //console.log("case 1: right sibling child red")
662 s = p.left = cloneNode(s)
663 z = s.right = cloneNode(s.right)
686 if(s._color === BLACK) {
687 if(p._color === RED) {
688 //console.log("case 2: black sibling, red parent")
690 p.left = repaint(RED, s)
693 //console.log("case 2: black sibling, black parent")
694 p.left = repaint(RED, s)
698 //console.log("case 3: red sibling")
716 if(i+1 < stack.length) {
727 //Removes item at iterator from tree
728 iproto.remove = function() {
729 var stack = this._stack
730 if(stack.length === 0) {
733 //First copy path to node
734 var cstack = new Array(stack.length)
735 var n = stack[stack.length-1]
736 cstack[cstack.length-1] = new RBNode(n._color, n.key, n.value, n.left, n.right, n._count)
737 for(var i=stack.length-2; i>=0; --i) {
739 if(n.left === stack[i+1]) {
740 cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i+1], n.right, n._count)
742 cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count)
747 n = cstack[cstack.length-1]
748 //console.log("start remove: ", n.value)
750 //If not leaf, then swap with previous node
751 if(n.left && n.right) {
752 //console.log("moving to leaf")
754 //First walk to previous leaf
755 var split = cstack.length
762 var v = cstack[split-1]
763 cstack.push(new RBNode(n._color, v.key, v.value, n.left, n.right, n._count))
764 cstack[split-1].key = n.key
765 cstack[split-1].value = n.value
768 for(var i=cstack.length-2; i>=split; --i) {
770 cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count)
772 cstack[split-1].left = cstack[split]
774 //console.log("stack=", cstack.map(function(v) { return v.value }))
777 n = cstack[cstack.length-1]
778 if(n._color === RED) {
779 //Easy case: removing red leaf
780 //console.log("RED leaf")
781 var p = cstack[cstack.length-2]
784 } else if(p.right === n) {
788 for(var i=0; i<cstack.length; ++i) {
791 return new RedBlackTree(this.tree._compare, cstack[0])
793 if(n.left || n.right) {
794 //Second easy case: Single child black parent
795 //console.log("BLACK single child")
801 //Child must be red, so repaint it black to balance color
803 for(var i=0; i<cstack.length-1; ++i) {
806 return new RedBlackTree(this.tree._compare, cstack[0])
807 } else if(cstack.length === 1) {
808 //Third easy case: root
809 //console.log("ROOT")
810 return new RedBlackTree(this.tree._compare, null)
812 //Hard case: Repaint n, and then do some nasty stuff
813 //console.log("BLACK leaf no children")
814 for(var i=0; i<cstack.length; ++i) {
817 var parent = cstack[cstack.length-2]
818 fixDoubleBlack(cstack)
820 if(parent.left === n) {
827 return new RedBlackTree(this.tree._compare, cstack[0])
831 Object.defineProperty(iproto, "key", {
833 if(this._stack.length > 0) {
834 return this._stack[this._stack.length-1].key
842 Object.defineProperty(iproto, "value", {
844 if(this._stack.length > 0) {
845 return this._stack[this._stack.length-1].value
853 //Returns the position of this iterator in the sorted list
854 Object.defineProperty(iproto, "index", {
857 var stack = this._stack
858 if(stack.length === 0) {
859 var r = this.tree.root
864 } else if(stack[stack.length-1].left) {
865 idx = stack[stack.length-1].left._count
867 for(var s=stack.length-2; s>=0; --s) {
868 if(stack[s+1] === stack[s].right) {
871 idx += stack[s].left._count
880 //Advances iterator to next element in list
881 iproto.next = function() {
882 var stack = this._stack
883 if(stack.length === 0) {
886 var n = stack[stack.length-1]
895 while(stack.length > 0 && stack[stack.length-1].right === n) {
896 n = stack[stack.length-1]
902 //Checks if iterator is at end of tree
903 Object.defineProperty(iproto, "hasNext", {
905 var stack = this._stack
906 if(stack.length === 0) {
909 if(stack[stack.length-1].right) {
912 for(var s=stack.length-1; s>0; --s) {
913 if(stack[s-1].left === stack[s]) {
922 iproto.update = function(value) {
923 var stack = this._stack
924 if(stack.length === 0) {
925 throw new Error("Can't update empty node!")
927 var cstack = new Array(stack.length)
928 var n = stack[stack.length-1]
929 cstack[cstack.length-1] = new RBNode(n._color, n.key, value, n.left, n.right, n._count)
930 for(var i=stack.length-2; i>=0; --i) {
932 if(n.left === stack[i+1]) {
933 cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i+1], n.right, n._count)
935 cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count)
938 return new RedBlackTree(this.tree._compare, cstack[0])
941 //Moves iterator backward one element
942 iproto.prev = function() {
943 var stack = this._stack
944 if(stack.length === 0) {
947 var n = stack[stack.length-1]
956 while(stack.length > 0 && stack[stack.length-1].left === n) {
957 n = stack[stack.length-1]
963 //Checks if iterator is at start of tree
964 Object.defineProperty(iproto, "hasPrev", {
966 var stack = this._stack
967 if(stack.length === 0) {
970 if(stack[stack.length-1].left) {
973 for(var s=stack.length-1; s>0; --s) {
974 if(stack[s-1].right === stack[s]) {
982 //Default comparison function
983 function defaultCompare(a, b) {
994 function createRBTree(compare) {
995 return new RedBlackTree(compare || defaultCompare, null)