123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996 |
- "use strict"
- module.exports = createRBTree
- var RED = 0
- var BLACK = 1
- function RBNode(color, key, value, left, right, count) {
- this._color = color
- this.key = key
- this.value = value
- this.left = left
- this.right = right
- this._count = count
- }
- function cloneNode(node) {
- return new RBNode(node._color, node.key, node.value, node.left, node.right, node._count)
- }
- function repaint(color, node) {
- return new RBNode(color, node.key, node.value, node.left, node.right, node._count)
- }
- function recount(node) {
- node._count = 1 + (node.left ? node.left._count : 0) + (node.right ? node.right._count : 0)
- }
- function RedBlackTree(compare, root) {
- this._compare = compare
- this.root = root
- }
- var proto = RedBlackTree.prototype
- Object.defineProperty(proto, "keys", {
- get: function() {
- var result = []
- this.forEach(function(k,v) {
- result.push(k)
- })
- return result
- }
- })
- Object.defineProperty(proto, "values", {
- get: function() {
- var result = []
- this.forEach(function(k,v) {
- result.push(v)
- })
- return result
- }
- })
- //Returns the number of nodes in the tree
- Object.defineProperty(proto, "length", {
- get: function() {
- if(this.root) {
- return this.root._count
- }
- return 0
- }
- })
- //Insert a new item into the tree
- proto.insert = function(key, value) {
- var cmp = this._compare
- //Find point to insert new node at
- var n = this.root
- var n_stack = []
- var d_stack = []
- while(n) {
- var d = cmp(key, n.key)
- n_stack.push(n)
- d_stack.push(d)
- if(d <= 0) {
- n = n.left
- } else {
- n = n.right
- }
- }
- //Rebuild path to leaf node
- n_stack.push(new RBNode(RED, key, value, null, null, 1))
- for(var s=n_stack.length-2; s>=0; --s) {
- var n = n_stack[s]
- if(d_stack[s] <= 0) {
- n_stack[s] = new RBNode(n._color, n.key, n.value, n_stack[s+1], n.right, n._count+1)
- } else {
- n_stack[s] = new RBNode(n._color, n.key, n.value, n.left, n_stack[s+1], n._count+1)
- }
- }
- //Rebalance tree using rotations
- //console.log("start insert", key, d_stack)
- for(var s=n_stack.length-1; s>1; --s) {
- var p = n_stack[s-1]
- var n = n_stack[s]
- if(p._color === BLACK || n._color === BLACK) {
- break
- }
- var pp = n_stack[s-2]
- if(pp.left === p) {
- if(p.left === n) {
- var y = pp.right
- if(y && y._color === RED) {
- //console.log("LLr")
- p._color = BLACK
- pp.right = repaint(BLACK, y)
- pp._color = RED
- s -= 1
- } else {
- //console.log("LLb")
- pp._color = RED
- pp.left = p.right
- p._color = BLACK
- p.right = pp
- n_stack[s-2] = p
- n_stack[s-1] = n
- recount(pp)
- recount(p)
- if(s >= 3) {
- var ppp = n_stack[s-3]
- if(ppp.left === pp) {
- ppp.left = p
- } else {
- ppp.right = p
- }
- }
- break
- }
- } else {
- var y = pp.right
- if(y && y._color === RED) {
- //console.log("LRr")
- p._color = BLACK
- pp.right = repaint(BLACK, y)
- pp._color = RED
- s -= 1
- } else {
- //console.log("LRb")
- p.right = n.left
- pp._color = RED
- pp.left = n.right
- n._color = BLACK
- n.left = p
- n.right = pp
- n_stack[s-2] = n
- n_stack[s-1] = p
- recount(pp)
- recount(p)
- recount(n)
- if(s >= 3) {
- var ppp = n_stack[s-3]
- if(ppp.left === pp) {
- ppp.left = n
- } else {
- ppp.right = n
- }
- }
- break
- }
- }
- } else {
- if(p.right === n) {
- var y = pp.left
- if(y && y._color === RED) {
- //console.log("RRr", y.key)
- p._color = BLACK
- pp.left = repaint(BLACK, y)
- pp._color = RED
- s -= 1
- } else {
- //console.log("RRb")
- pp._color = RED
- pp.right = p.left
- p._color = BLACK
- p.left = pp
- n_stack[s-2] = p
- n_stack[s-1] = n
- recount(pp)
- recount(p)
- if(s >= 3) {
- var ppp = n_stack[s-3]
- if(ppp.right === pp) {
- ppp.right = p
- } else {
- ppp.left = p
- }
- }
- break
- }
- } else {
- var y = pp.left
- if(y && y._color === RED) {
- //console.log("RLr")
- p._color = BLACK
- pp.left = repaint(BLACK, y)
- pp._color = RED
- s -= 1
- } else {
- //console.log("RLb")
- p.left = n.right
- pp._color = RED
- pp.right = n.left
- n._color = BLACK
- n.right = p
- n.left = pp
- n_stack[s-2] = n
- n_stack[s-1] = p
- recount(pp)
- recount(p)
- recount(n)
- if(s >= 3) {
- var ppp = n_stack[s-3]
- if(ppp.right === pp) {
- ppp.right = n
- } else {
- ppp.left = n
- }
- }
- break
- }
- }
- }
- }
- //Return new tree
- n_stack[0]._color = BLACK
- return new RedBlackTree(cmp, n_stack[0])
- }
- //Visit all nodes inorder
- function doVisitFull(visit, node) {
- if(node.left) {
- var v = doVisitFull(visit, node.left)
- if(v) { return v }
- }
- var v = visit(node.key, node.value)
- if(v) { return v }
- if(node.right) {
- return doVisitFull(visit, node.right)
- }
- }
- //Visit half nodes in order
- function doVisitHalf(lo, compare, visit, node) {
- var l = compare(lo, node.key)
- if(l <= 0) {
- if(node.left) {
- var v = doVisitHalf(lo, compare, visit, node.left)
- if(v) { return v }
- }
- var v = visit(node.key, node.value)
- if(v) { return v }
- }
- if(node.right) {
- return doVisitHalf(lo, compare, visit, node.right)
- }
- }
- //Visit all nodes within a range
- function doVisit(lo, hi, compare, visit, node) {
- var l = compare(lo, node.key)
- var h = compare(hi, node.key)
- var v
- if(l <= 0) {
- if(node.left) {
- v = doVisit(lo, hi, compare, visit, node.left)
- if(v) { return v }
- }
- if(h > 0) {
- v = visit(node.key, node.value)
- if(v) { return v }
- }
- }
- if(h > 0 && node.right) {
- return doVisit(lo, hi, compare, visit, node.right)
- }
- }
- proto.forEach = function rbTreeForEach(visit, lo, hi) {
- if(!this.root) {
- return
- }
- switch(arguments.length) {
- case 1:
- return doVisitFull(visit, this.root)
- break
- case 2:
- return doVisitHalf(lo, this._compare, visit, this.root)
- break
- case 3:
- if(this._compare(lo, hi) >= 0) {
- return
- }
- return doVisit(lo, hi, this._compare, visit, this.root)
- break
- }
- }
- //First item in list
- Object.defineProperty(proto, "begin", {
- get: function() {
- var stack = []
- var n = this.root
- while(n) {
- stack.push(n)
- n = n.left
- }
- return new RedBlackTreeIterator(this, stack)
- }
- })
- //Last item in list
- Object.defineProperty(proto, "end", {
- get: function() {
- var stack = []
- var n = this.root
- while(n) {
- stack.push(n)
- n = n.right
- }
- return new RedBlackTreeIterator(this, stack)
- }
- })
- //Find the ith item in the tree
- proto.at = function(idx) {
- if(idx < 0) {
- return new RedBlackTreeIterator(this, [])
- }
- var n = this.root
- var stack = []
- while(true) {
- stack.push(n)
- if(n.left) {
- if(idx < n.left._count) {
- n = n.left
- continue
- }
- idx -= n.left._count
- }
- if(!idx) {
- return new RedBlackTreeIterator(this, stack)
- }
- idx -= 1
- if(n.right) {
- if(idx >= n.right._count) {
- break
- }
- n = n.right
- } else {
- break
- }
- }
- return new RedBlackTreeIterator(this, [])
- }
- proto.ge = function(key) {
- var cmp = this._compare
- var n = this.root
- var stack = []
- var last_ptr = 0
- while(n) {
- var d = cmp(key, n.key)
- stack.push(n)
- if(d <= 0) {
- last_ptr = stack.length
- }
- if(d <= 0) {
- n = n.left
- } else {
- n = n.right
- }
- }
- stack.length = last_ptr
- return new RedBlackTreeIterator(this, stack)
- }
- proto.gt = function(key) {
- var cmp = this._compare
- var n = this.root
- var stack = []
- var last_ptr = 0
- while(n) {
- var d = cmp(key, n.key)
- stack.push(n)
- if(d < 0) {
- last_ptr = stack.length
- }
- if(d < 0) {
- n = n.left
- } else {
- n = n.right
- }
- }
- stack.length = last_ptr
- return new RedBlackTreeIterator(this, stack)
- }
- proto.lt = function(key) {
- var cmp = this._compare
- var n = this.root
- var stack = []
- var last_ptr = 0
- while(n) {
- var d = cmp(key, n.key)
- stack.push(n)
- if(d > 0) {
- last_ptr = stack.length
- }
- if(d <= 0) {
- n = n.left
- } else {
- n = n.right
- }
- }
- stack.length = last_ptr
- return new RedBlackTreeIterator(this, stack)
- }
- proto.le = function(key) {
- var cmp = this._compare
- var n = this.root
- var stack = []
- var last_ptr = 0
- while(n) {
- var d = cmp(key, n.key)
- stack.push(n)
- if(d >= 0) {
- last_ptr = stack.length
- }
- if(d < 0) {
- n = n.left
- } else {
- n = n.right
- }
- }
- stack.length = last_ptr
- return new RedBlackTreeIterator(this, stack)
- }
- //Finds the item with key if it exists
- proto.find = function(key) {
- var cmp = this._compare
- var n = this.root
- var stack = []
- while(n) {
- var d = cmp(key, n.key)
- stack.push(n)
- if(d === 0) {
- return new RedBlackTreeIterator(this, stack)
- }
- if(d <= 0) {
- n = n.left
- } else {
- n = n.right
- }
- }
- return new RedBlackTreeIterator(this, [])
- }
- //Removes item with key from tree
- proto.remove = function(key) {
- var iter = this.find(key)
- if(iter) {
- return iter.remove()
- }
- return this
- }
- //Returns the item at `key`
- proto.get = function(key) {
- var cmp = this._compare
- var n = this.root
- while(n) {
- var d = cmp(key, n.key)
- if(d === 0) {
- return n.value
- }
- if(d <= 0) {
- n = n.left
- } else {
- n = n.right
- }
- }
- return
- }
- //Iterator for red black tree
- function RedBlackTreeIterator(tree, stack) {
- this.tree = tree
- this._stack = stack
- }
- var iproto = RedBlackTreeIterator.prototype
- //Test if iterator is valid
- Object.defineProperty(iproto, "valid", {
- get: function() {
- return this._stack.length > 0
- }
- })
- //Node of the iterator
- Object.defineProperty(iproto, "node", {
- get: function() {
- if(this._stack.length > 0) {
- return this._stack[this._stack.length-1]
- }
- return null
- },
- enumerable: true
- })
- //Makes a copy of an iterator
- iproto.clone = function() {
- return new RedBlackTreeIterator(this.tree, this._stack.slice())
- }
- //Swaps two nodes
- function swapNode(n, v) {
- n.key = v.key
- n.value = v.value
- n.left = v.left
- n.right = v.right
- n._color = v._color
- n._count = v._count
- }
- //Fix up a double black node in a tree
- function fixDoubleBlack(stack) {
- var n, p, s, z
- for(var i=stack.length-1; i>=0; --i) {
- n = stack[i]
- if(i === 0) {
- n._color = BLACK
- return
- }
- //console.log("visit node:", n.key, i, stack[i].key, stack[i-1].key)
- p = stack[i-1]
- if(p.left === n) {
- //console.log("left child")
- s = p.right
- if(s.right && s.right._color === RED) {
- //console.log("case 1: right sibling child red")
- s = p.right = cloneNode(s)
- z = s.right = cloneNode(s.right)
- p.right = s.left
- s.left = p
- s.right = z
- s._color = p._color
- n._color = BLACK
- p._color = BLACK
- z._color = BLACK
- recount(p)
- recount(s)
- if(i > 1) {
- var pp = stack[i-2]
- if(pp.left === p) {
- pp.left = s
- } else {
- pp.right = s
- }
- }
- stack[i-1] = s
- return
- } else if(s.left && s.left._color === RED) {
- //console.log("case 1: left sibling child red")
- s = p.right = cloneNode(s)
- z = s.left = cloneNode(s.left)
- p.right = z.left
- s.left = z.right
- z.left = p
- z.right = s
- z._color = p._color
- p._color = BLACK
- s._color = BLACK
- n._color = BLACK
- recount(p)
- recount(s)
- recount(z)
- if(i > 1) {
- var pp = stack[i-2]
- if(pp.left === p) {
- pp.left = z
- } else {
- pp.right = z
- }
- }
- stack[i-1] = z
- return
- }
- if(s._color === BLACK) {
- if(p._color === RED) {
- //console.log("case 2: black sibling, red parent", p.right.value)
- p._color = BLACK
- p.right = repaint(RED, s)
- return
- } else {
- //console.log("case 2: black sibling, black parent", p.right.value)
- p.right = repaint(RED, s)
- continue
- }
- } else {
- //console.log("case 3: red sibling")
- s = cloneNode(s)
- p.right = s.left
- s.left = p
- s._color = p._color
- p._color = RED
- recount(p)
- recount(s)
- if(i > 1) {
- var pp = stack[i-2]
- if(pp.left === p) {
- pp.left = s
- } else {
- pp.right = s
- }
- }
- stack[i-1] = s
- stack[i] = p
- if(i+1 < stack.length) {
- stack[i+1] = n
- } else {
- stack.push(n)
- }
- i = i+2
- }
- } else {
- //console.log("right child")
- s = p.left
- if(s.left && s.left._color === RED) {
- //console.log("case 1: left sibling child red", p.value, p._color)
- s = p.left = cloneNode(s)
- z = s.left = cloneNode(s.left)
- p.left = s.right
- s.right = p
- s.left = z
- s._color = p._color
- n._color = BLACK
- p._color = BLACK
- z._color = BLACK
- recount(p)
- recount(s)
- if(i > 1) {
- var pp = stack[i-2]
- if(pp.right === p) {
- pp.right = s
- } else {
- pp.left = s
- }
- }
- stack[i-1] = s
- return
- } else if(s.right && s.right._color === RED) {
- //console.log("case 1: right sibling child red")
- s = p.left = cloneNode(s)
- z = s.right = cloneNode(s.right)
- p.left = z.right
- s.right = z.left
- z.right = p
- z.left = s
- z._color = p._color
- p._color = BLACK
- s._color = BLACK
- n._color = BLACK
- recount(p)
- recount(s)
- recount(z)
- if(i > 1) {
- var pp = stack[i-2]
- if(pp.right === p) {
- pp.right = z
- } else {
- pp.left = z
- }
- }
- stack[i-1] = z
- return
- }
- if(s._color === BLACK) {
- if(p._color === RED) {
- //console.log("case 2: black sibling, red parent")
- p._color = BLACK
- p.left = repaint(RED, s)
- return
- } else {
- //console.log("case 2: black sibling, black parent")
- p.left = repaint(RED, s)
- continue
- }
- } else {
- //console.log("case 3: red sibling")
- s = cloneNode(s)
- p.left = s.right
- s.right = p
- s._color = p._color
- p._color = RED
- recount(p)
- recount(s)
- if(i > 1) {
- var pp = stack[i-2]
- if(pp.right === p) {
- pp.right = s
- } else {
- pp.left = s
- }
- }
- stack[i-1] = s
- stack[i] = p
- if(i+1 < stack.length) {
- stack[i+1] = n
- } else {
- stack.push(n)
- }
- i = i+2
- }
- }
- }
- }
- //Removes item at iterator from tree
- iproto.remove = function() {
- var stack = this._stack
- if(stack.length === 0) {
- return this.tree
- }
- //First copy path to node
- var cstack = new Array(stack.length)
- var n = stack[stack.length-1]
- cstack[cstack.length-1] = new RBNode(n._color, n.key, n.value, n.left, n.right, n._count)
- for(var i=stack.length-2; i>=0; --i) {
- var n = stack[i]
- if(n.left === stack[i+1]) {
- cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i+1], n.right, n._count)
- } else {
- cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count)
- }
- }
- //Get node
- n = cstack[cstack.length-1]
- //console.log("start remove: ", n.value)
- //If not leaf, then swap with previous node
- if(n.left && n.right) {
- //console.log("moving to leaf")
- //First walk to previous leaf
- var split = cstack.length
- n = n.left
- while(n.right) {
- cstack.push(n)
- n = n.right
- }
- //Copy path to leaf
- var v = cstack[split-1]
- cstack.push(new RBNode(n._color, v.key, v.value, n.left, n.right, n._count))
- cstack[split-1].key = n.key
- cstack[split-1].value = n.value
- //Fix up stack
- for(var i=cstack.length-2; i>=split; --i) {
- n = cstack[i]
- cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count)
- }
- cstack[split-1].left = cstack[split]
- }
- //console.log("stack=", cstack.map(function(v) { return v.value }))
- //Remove leaf node
- n = cstack[cstack.length-1]
- if(n._color === RED) {
- //Easy case: removing red leaf
- //console.log("RED leaf")
- var p = cstack[cstack.length-2]
- if(p.left === n) {
- p.left = null
- } else if(p.right === n) {
- p.right = null
- }
- cstack.pop()
- for(var i=0; i<cstack.length; ++i) {
- cstack[i]._count--
- }
- return new RedBlackTree(this.tree._compare, cstack[0])
- } else {
- if(n.left || n.right) {
- //Second easy case: Single child black parent
- //console.log("BLACK single child")
- if(n.left) {
- swapNode(n, n.left)
- } else if(n.right) {
- swapNode(n, n.right)
- }
- //Child must be red, so repaint it black to balance color
- n._color = BLACK
- for(var i=0; i<cstack.length-1; ++i) {
- cstack[i]._count--
- }
- return new RedBlackTree(this.tree._compare, cstack[0])
- } else if(cstack.length === 1) {
- //Third easy case: root
- //console.log("ROOT")
- return new RedBlackTree(this.tree._compare, null)
- } else {
- //Hard case: Repaint n, and then do some nasty stuff
- //console.log("BLACK leaf no children")
- for(var i=0; i<cstack.length; ++i) {
- cstack[i]._count--
- }
- var parent = cstack[cstack.length-2]
- fixDoubleBlack(cstack)
- //Fix up links
- if(parent.left === n) {
- parent.left = null
- } else {
- parent.right = null
- }
- }
- }
- return new RedBlackTree(this.tree._compare, cstack[0])
- }
- //Returns key
- Object.defineProperty(iproto, "key", {
- get: function() {
- if(this._stack.length > 0) {
- return this._stack[this._stack.length-1].key
- }
- return
- },
- enumerable: true
- })
- //Returns value
- Object.defineProperty(iproto, "value", {
- get: function() {
- if(this._stack.length > 0) {
- return this._stack[this._stack.length-1].value
- }
- return
- },
- enumerable: true
- })
- //Returns the position of this iterator in the sorted list
- Object.defineProperty(iproto, "index", {
- get: function() {
- var idx = 0
- var stack = this._stack
- if(stack.length === 0) {
- var r = this.tree.root
- if(r) {
- return r._count
- }
- return 0
- } else if(stack[stack.length-1].left) {
- idx = stack[stack.length-1].left._count
- }
- for(var s=stack.length-2; s>=0; --s) {
- if(stack[s+1] === stack[s].right) {
- ++idx
- if(stack[s].left) {
- idx += stack[s].left._count
- }
- }
- }
- return idx
- },
- enumerable: true
- })
- //Advances iterator to next element in list
- iproto.next = function() {
- var stack = this._stack
- if(stack.length === 0) {
- return
- }
- var n = stack[stack.length-1]
- if(n.right) {
- n = n.right
- while(n) {
- stack.push(n)
- n = n.left
- }
- } else {
- stack.pop()
- while(stack.length > 0 && stack[stack.length-1].right === n) {
- n = stack[stack.length-1]
- stack.pop()
- }
- }
- }
- //Checks if iterator is at end of tree
- Object.defineProperty(iproto, "hasNext", {
- get: function() {
- var stack = this._stack
- if(stack.length === 0) {
- return false
- }
- if(stack[stack.length-1].right) {
- return true
- }
- for(var s=stack.length-1; s>0; --s) {
- if(stack[s-1].left === stack[s]) {
- return true
- }
- }
- return false
- }
- })
- //Update value
- iproto.update = function(value) {
- var stack = this._stack
- if(stack.length === 0) {
- throw new Error("Can't update empty node!")
- }
- var cstack = new Array(stack.length)
- var n = stack[stack.length-1]
- cstack[cstack.length-1] = new RBNode(n._color, n.key, value, n.left, n.right, n._count)
- for(var i=stack.length-2; i>=0; --i) {
- n = stack[i]
- if(n.left === stack[i+1]) {
- cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i+1], n.right, n._count)
- } else {
- cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count)
- }
- }
- return new RedBlackTree(this.tree._compare, cstack[0])
- }
- //Moves iterator backward one element
- iproto.prev = function() {
- var stack = this._stack
- if(stack.length === 0) {
- return
- }
- var n = stack[stack.length-1]
- if(n.left) {
- n = n.left
- while(n) {
- stack.push(n)
- n = n.right
- }
- } else {
- stack.pop()
- while(stack.length > 0 && stack[stack.length-1].left === n) {
- n = stack[stack.length-1]
- stack.pop()
- }
- }
- }
- //Checks if iterator is at start of tree
- Object.defineProperty(iproto, "hasPrev", {
- get: function() {
- var stack = this._stack
- if(stack.length === 0) {
- return false
- }
- if(stack[stack.length-1].left) {
- return true
- }
- for(var s=stack.length-1; s>0; --s) {
- if(stack[s-1].right === stack[s]) {
- return true
- }
- }
- return false
- }
- })
- //Default comparison function
- function defaultCompare(a, b) {
- if(a < b) {
- return -1
- }
- if(a > b) {
- return 1
- }
- return 0
- }
- //Build a tree
- function createRBTree(compare) {
- return new RedBlackTree(compare || defaultCompare, null)
- }
|