Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //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])
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement