//<script type="text/javascript">
//
// RBTree.js
// implementation of a red black tree
//
// Free Software Licence:
// This software is intended for free use for personal and comercial use.
// No Warranty:
// Because this software is licenced free of charge, there is no warranty
// expressed or implied for any code contained within this file.
// Guyon Roche
// logical xor of b1 and b2
function xor(b1,b2)
{
return (b1 && !b2) || (!b1 && b2);
}
// head and tail are sentinel nodes not stored in the tree
this.head = {item:"head",prev:null,bSentinel:true};
this.tail = {item:"tail",tail:null,bSentinel:true};
this.head.next = this.tail;
this.tail.prev = this.head;
}
RBTree.prototype.insert = function(value,hint)
{
var node = new RBTreeNode(value,this);
// account for size
if ( !this.nSize++ )
{
this.root = node;
node.listInsert(this.head,this.tail);
node.parent = null;
return node;
}
var pos = this.root;
// if hint exists, assume upper bound - 1
if ( hint && hint.bSentinel )
{
if ( hint === this.head ) hint = hint.next;
else if ( hint === this.tail ) hint = hint.prev;
else hint = null;
}
if ( hint && (hint.tree === this) ) pos = hint;
pos.insert(node, this.less);
node.balance();
// make root node black
this.root.bBlack = 1;
return node;
}
RBTree.prototype.remove = function(node)
{
// remove the node from the tree returning the node that follows.
// protect and serve
if ( node.tree !== this ) return this.tail;
// account for size
if ( --this.nSize == 0 )
{
this.root = null;
node.listRemove();
return this.tail;
}
var next = node.next;
// case 1: node has two children or is root
if ( !node.parent || (node.left.bNode && node.right.bNode) )
{
// find inorder predecessor (or successor) and swap values
// after deletion, value order will be preserved
var sub = node.prev;
if ( !sub )
{
sub = node.next;
next = node;
}
node.item = sub.item;
node = sub;
}
// node now has at most one child node
// remove node from linked list
node.listRemove();
// p is parent of node
var p = node.parent;
var bLeft = (node === p.left);
// c is child of node
var c = node.left.bNode ? node.left : node.right;
// move c into place
c.parent = node.parent;
if ( bLeft ) p.left = c; else p.right = c;
// node is red
if ( !node.bBlack )
{
// this is easy, colour c black and return
c.bBlack = 1;
return next;
}
// node is black, add to c and fix
c.bBlack++;
if ( c.bBlack > 1 ) c.fix();
return next;
}
//Returns an iterator to the first element in a set that with a key that is
//greater than a specified key.
RBTree.prototype.upper_bound = function(value)
{
if ( !this.root ) return this.tail;
return this.root.upper_bound(value,this.less);
}
//Returns an iterator to the first element in a map that with a key value that is
//equal to or greater than that of a specified key.
RBTree.prototype.lower_bound = function(value)
{
if ( !this.root ) return this.tail;
else return this.root.lower_bound(value, this.less);
}
this.next = next;
next.prev = this;
}
RBTreeNode.prototype.listRemove = function()
{
this.next.prev = this.prev;
this.prev.next = this.next;
}
RBTreeNode.prototype.insertChild = function(prev,next,node)
{
node.parent = this;
node.listInsert(prev,next);
}
RBTreeNode.prototype.insert = function(node, less)
{
// simple binary insertion
if ( less.fn(node.item,this.item) )
{
if ( this.left.bNode ) this.left.insert(node,less);
else this.insertChild(this.prev,this,this.left = node);
}
else
{
if ( this.right.bNode ) this.right.insert(node,less);
else this.insertChild(this,this.next,this.right = node);
}
}
RBTreeNode.prototype.balance = function()
{
// walk up the tree preserving the red-black rules
// p is parent
var p = this.parent;
// case 1: this is root node or parent is black
if ( !p || (p.bBlack != 0) ) return;
// g is grand parent
var g = p.parent;
// case 1b: p is root node
if ( !g ) return;
// record whether we are the left child
var bLeft = (this === p.left);
// and whether parent is a left child
var bPLeft = (p === g.left);
// u is uncle
var u = (bPLeft ? g.right : g.left);
// case 2: parent is red, uncle is black
if ( u.bBlack != 0 )
{
if ( xor(bLeft,bPLeft) )
{
// case 2a: parent is different handed to this
this.rotate();
this.rotate();
}
else
{
// case 2b: parent is same handed as this
p.rotate();
}
return;
}
// case 3: parent is red, uncle is red
p.bBlack = 1;
u.bBlack = 1;
g.bBlack = 0;
g.balance();
}
RBTreeNode.prototype.rotate = function()
{
// p is parent
var p = this.parent;
// if this is root node, we can't rotate
if ( !p ) return;
// s is sibling
var s = (this === p.left) ? p.right : p.left;
// case 1: black sibling with red child
if ( s.bBlack && s.bNode )
{
var n = null;
if ( !s.left.bBlack ) n = s.left;
else if ( !s.right.bBlack ) n = s.right;
if ( n )
{
// restructure
this.bBlack = 1;
n.bBlack = 1;
if ( !xor((s===p.left),(n===s.left)) )
{
// s and n same handed
s.rotate();
}
else
{
// s and n different handed
n.rotate();
n.rotate();
}
return;
}
}
// case 2: black sibling without (red) children
if ( s.bBlack )
{
// recolour
this.bBlack = 1;
s.bBlack = 0;
if ( ++p.bBlack > 1 ) p.fix();
return;
}
// case 3: red sibling --> adjustment
s.rotate();
this.fix();
}
//Returns node of the first element in a set that with a key that is
//greater than a specified key.
RBTreeNode.prototype.upper_bound = function(value,less)
{
if ( !less.fn(value,this.item) )
{
// value >= this.item
if ( this.right.bNode ) return this.right.upper_bound(value,less);
else return this.next;
}
else
{
// value < this.item
if ( this.left.bNode ) return this.left.upper_bound(value,less);
else return this;
}
}
//Returns node of the first element in a map that with a key value that is
//equal to or greater than that of a specified key.
RBTreeNode.prototype.lower_bound = function(value,less)
{
if ( less.fn(this.item,value) )
{
// value > this.item
if ( this.right.bNode ) return this.right.lower_bound(value,less);
else return this.next;
}
else
{
// value <= this.item
if ( this.left.bNode ) return this.left.lower_bound(value,less);
else return this;
}
}