| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996 | "use strict"module.exports = createRBTreevar RED   = 0var BLACK = 1function 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.prototypeObject.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 treeObject.defineProperty(proto, "length", {  get: function() {    if(this.root) {      return this.root._count    }    return 0  }})//Insert a new item into the treeproto.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 inorderfunction 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 orderfunction 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 rangefunction 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 listObject.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 listObject.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 treeproto.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 existsproto.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 treeproto.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 treefunction RedBlackTreeIterator(tree, stack) {  this.tree = tree  this._stack = stack}var iproto = RedBlackTreeIterator.prototype//Test if iterator is validObject.defineProperty(iproto, "valid", {  get: function() {    return this._stack.length > 0  }})//Node of the iteratorObject.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 iteratoriproto.clone = function() {  return new RedBlackTreeIterator(this.tree, this._stack.slice())}//Swaps two nodesfunction 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 treefunction 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 treeiproto.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 keyObject.defineProperty(iproto, "key", {  get: function() {    if(this._stack.length > 0) {      return this._stack[this._stack.length-1].key    }    return  },  enumerable: true})//Returns valueObject.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 listObject.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 listiproto.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 treeObject.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 valueiproto.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 elementiproto.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 treeObject.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 functionfunction defaultCompare(a, b) {  if(a < b) {    return -1  }  if(a > b) {    return 1  }  return 0}//Build a treefunction createRBTree(compare) {  return new RedBlackTree(compare || defaultCompare, null)}
 |