Advertisement
rnort

RBTree-JavaScript

Dec 10th, 2012
349
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. function RBTree()
  2. {
  3.     this.nil = new RBNode();
  4.     this.nil.left = this.nil.right = this.nil.parent = this.nil;
  5.     this.root = this.nil;
  6. }
  7.  
  8.  
  9. RBTree.prototype.forEach = function(func) {
  10.     this.inorderTraversal(this.root.left, func);
  11. };
  12.  
  13. RBTree.prototype.inorderTraversal = function(x, func){
  14.     if( x !== this.nil){
  15.         this.inorderTraversal(x.left, func);
  16.         func(x);
  17.         this.inorderTraversal(x.right, func);
  18.     }
  19. }
  20.  
  21. RBTree.prototype.toarrayTraversal = function(x, array) {
  22.     if( x !== this.nil){
  23.         array = this.toarrayTraversal(x.left, array);
  24.         array.push(x);
  25.         array = this.toarrayTraversal(x.right, array);
  26.     }
  27.     return array;  
  28. };
  29.  
  30. RBTree.prototype.toString = function() {
  31.     return this.toArray().toString();
  32. };
  33.  
  34. RBTree.prototype.toArray = function() {
  35.     return this.toarrayTraversal(this.root.left, []);
  36. };
  37.  
  38. RBTree.prototype.count = function() {
  39.     return this.toArray().length;
  40. };
  41.  
  42. // Get value associated with given key
  43. RBTree.prototype.get = function(key) {
  44.     var node = this.findKey(key);
  45.     return  node ? node.value : node;
  46. };
  47.  
  48. RBTree.prototype.set = function(key, value){
  49.     this.findKey(key, value);
  50.     this.notify("onchange");
  51. };
  52.  
  53. RBTree.prototype.findKey = function(key, value) {
  54.     if ( key == null) return null;
  55.     var x = this.root.left;
  56.     if ( x === this.nil){
  57.         return null;
  58.     }
  59.     var isEqual = this.compare( x.key, key);
  60.     while ( isEqual !== 0)
  61.     {
  62.         x = isEqual === 1 ? x.left : x.right;
  63.         if( x === this.nil){
  64.             return null;
  65.         }
  66.         isEqual = this.compare(x.key, key);
  67.     }
  68.     x.value = value ? value : x.value;
  69.     return x;
  70. };
  71.  
  72. RBTree.prototype.compare = function( a, b){
  73.     if (a === b) return 0;
  74.     if (typeof a === typeof b){
  75.         return a < b ? -1 : 1;
  76.     }
  77.     else{
  78.         throw "Invalid type of arguments";
  79.     }
  80. };
  81.  
  82. RBTree.prototype.addEventListener = function(event, listener) {
  83.     if ( this.listeners == null || this.listeners == undefined){
  84.         this.listeners = [];
  85.     }
  86.     if ( this.listeners[event] == null || this.listeners[event] == undefined){
  87.         this.listeners[event] = [];
  88.     }
  89.     this.listeners[event].push(listener);
  90. };
  91.  
  92. RBTree.prototype.removeEventListener = function(event, listener) {
  93.     if ( this.listeners[event] == null || this.listeners[event] == undefined){
  94.         return;
  95.     }
  96.     for ( var i = 0; i < this.listeners[event].length; ++i){
  97.         if (this.listeners[event][i] === listener){
  98.             this.listeners[event].splice(i, 1);
  99.         }
  100.         --i;
  101.     }
  102. };
  103.  
  104. RBTree.prototype.notify = function(event) {
  105.     if ( this.listeners == null || this.listeners == undefined){
  106.         return;
  107.     }
  108.     if ( this.listeners[event] == null || this.listeners[event] == undefined){
  109.         return;
  110.     }
  111.  
  112.     for (var i = 0; i < this.listeners[event].length; ++i){
  113.         this.listeners[event][i](this);
  114.     }
  115. };
  116.  
  117. RBTree.prototype.insert = function(key, value) {
  118.     if ( key == null || value == null )
  119.     {
  120.         throw "Arguments not valid";
  121.     }
  122.     var newnode = new RBNode(key, value);
  123.     var node = newnode;
  124.     var tmpnode = null;
  125.     this.BSTreeInsert(node);
  126.     node.color = RBNode.COLOR_RED;
  127.     while(node.parent.color === RBNode.COLOR_RED){
  128.         if(node.parent === node.parent.parent.left){
  129.             tmpnode = node.parent.parent.right;
  130.             if( tmpnode.color === RBNode.COLOR_RED){
  131.                 node.parent.color = RBNode.COLOR_BLACK;
  132.                 tmpnode.color = RBNode.COLOR_BLACK;
  133.                 node.parent.parent.color = RBNode.COLOR_RED;
  134.                 node = node.parent.parent;
  135.             }
  136.             else{
  137.                 if( node === node.parent.right){
  138.                     node = node.parent;
  139.                     this.leftRotate( node);
  140.                 }
  141.                 node.parent.color = RBNode.COLOR_BLACK;
  142.                 node.parent.parent.color = RBNode.COLOR_RED;
  143.                 this.rightRotate( node.parent.parent);
  144.             }
  145.         }
  146.         else{
  147.             tmpnode = node.parent.parent.left;
  148.             if(tmpnode.color === RBNode.COLOR_RED){
  149.                 node.parent.color = RBNode.COLOR_BLACK;
  150.                 tmpnode.color = RBNode.COLOR_BLACK;
  151.                 node.parent.parent.color = RBNode.COLOR_RED;
  152.                 node = node.parent.parent;
  153.             }
  154.             else{
  155.                 if( node === node.parent.left){
  156.                     node = node.parent;
  157.                     this.rightRotate(node);
  158.                 }
  159.                 node.parent.color = RBNode.COLOR_BLACK;
  160.                 node.parent.parent.color = RBNode.COLOR_RED;
  161.                 this.leftRotate(node.parent.parent);
  162.             }
  163.         }
  164.     }
  165.     this.root.left.color = RBNode.COLOR_BLACK;
  166.     this.notify("onchange");
  167.     return newnode;
  168. };
  169.  
  170. RBTree.prototype.thisSuccessor = function(x) {
  171.     var root = this.root;
  172.     var y = x.right;
  173.     if(y !== this.nil){
  174.         while(y.left !== this.nil){
  175.             y = y.left;
  176.         }
  177.         return y;
  178.     }
  179.     else{
  180.         y = x.parent;
  181.         while( x === y.right){
  182.             x = y;
  183.             y = y.parent;
  184.         }
  185.         if( y === root){
  186.             return this.nil;
  187.         }
  188.         return y;
  189.     }
  190. };
  191.  
  192. RBTree.prototype.thisPredecessor = function(x) {
  193.     var root = this.root;
  194.     var y = x.left;
  195.     if( y !== this.nil){
  196.         while( y.right !== this.nil){
  197.             y = y.right;
  198.         }
  199.         return y;
  200.     }
  201.     else{
  202.         y = x.parent;
  203.         while( x === y.left){
  204.             if(y === root){
  205.                 return this.nil;
  206.             }
  207.             x = y;
  208.             y = y.parent;
  209.         }
  210.         return y;
  211.     }
  212. };
  213.  
  214. RBTree.prototype.delete = function( item ) {
  215.     if ( typeof item != RBNode){
  216.         item = this.findKey(item);
  217.     }
  218.     if ( item == null || item == undefined ) throw "Invalid argument";
  219.  
  220.     var root = this.root;
  221.     var y = null, x = null;
  222.  
  223.     if( item.left === this.nil || item.right === this.nil){
  224.         y = item;
  225.     }
  226.     else{
  227.         y = this.thisPredecessor(item);
  228.     }
  229.  
  230.     if( y.left === this.nil){
  231.         x = y.right;
  232.     }
  233.     else{
  234.         x = y.left;
  235.     }
  236.     x.parent = y.parent;
  237.     if( root === x.parent){
  238.         root.left = x;
  239.     }
  240.     else{
  241.         if( y === y.parent.left){
  242.             y.parent.left = x;
  243.         }
  244.         else{
  245.             y.parent.right = x;
  246.         }
  247.     }
  248.  
  249.     if( y !== item){
  250.         if(y.color === RBNode.COLOR_BLACK){
  251.             this.deleteFixup(x);
  252.         }
  253.  
  254.         y.left = item.left;
  255.         y.right = item.right;
  256.         y.parent = item.parent;
  257.         y.color = item.color;
  258.         item.left.parent = item.right.parent = y;
  259.  
  260.         if(item === item.parent.left){
  261.             item.parent.left = y;
  262.         }
  263.         else{
  264.             item.parent.right = y;
  265.         }
  266.     }
  267.     else{
  268.         if( y.color === RBNode.COLOR_BLACK){
  269.             this.deleteFixup(x);
  270.         }
  271.     }
  272.     if ( this.count() == 0){
  273.         this.notify("onempty");
  274.     }
  275. };
  276.  
  277. RBTree.prototype.leftRotate = function(x) {
  278.  
  279.     var y = x.right;
  280.     x.right = y.left;
  281.     if( y.left !== this.nil){
  282.         y.left.parent = x;
  283.     }
  284.     y.parent = x.parent;
  285.     if(x === x.parent.left){
  286.         x.parent.left = y;
  287.     }
  288.     else{
  289.         x.parent.right = y;
  290.     }
  291.     y.left = x;
  292.     x.parent = y;
  293. };
  294.  
  295. RBTree.prototype.rightRotate = function( y) {
  296.     var x = y.left;
  297.     y.left = x.right;
  298.  
  299.     if(x.right !== this.nil){
  300.         x.right.parent = y;
  301.     }
  302.  
  303.     x.parent = y.parent;
  304.  
  305.     if( y === y.parent.left){
  306.         y.parent.left = x;
  307.     }
  308.     else{
  309.         y.parent.right = x;
  310.     }
  311.     x.right = y;
  312.     y.parent = x;
  313. };
  314.  
  315. RBTree.prototype.BSTreeInsert = function(node) {
  316.     var root = this.root;
  317.     var x = this.root.left;
  318.     node.left = node.right = this.nil;
  319.     while( x !== this.nil){
  320.         root = x;
  321.         if( this.compare( x.key, node.key) === 1){
  322.             x = x.left;
  323.         }
  324.         else{
  325.             x = x.right;
  326.         }
  327.     }
  328.  
  329.     node.parent = root;
  330.     if( root === this.root ||
  331.         this.compare(root.key, node.key) === 1){
  332.         root.left = node;
  333.     }
  334.     else{
  335.         root.right = node;
  336.     }
  337. };
  338.  
  339. RBTree.prototype.deleteFixup = function(x) {
  340.     var root = this.root.left;
  341.     var w = null;
  342.     while( x.color === RBNode.COLOR_BLACK && root !== x){
  343.  
  344.         if(x === x.parent.left){
  345.             w = x.parent.right;
  346.             if( w.color === RBNode.COLOR_RED){
  347.                 w.color = RBNode.COLOR_BLACK;
  348.                 x.parent.color = RBNode.COLOR_RED;
  349.                 this.leftRotate( x.parent);
  350.                 w = x.parent.right;
  351.             }
  352.  
  353.             if ( w.right.color === RBNode.COLOR_BLACK &&
  354.                 w.left.color === RBNode.COLOR_BLACK){
  355.                
  356.                 w.color = RBNode.COLOR_RED;
  357.                 x = x.parent;
  358.             }
  359.             else{
  360.                 if ( w.right.color === RBNode.COLOR_BLACK){
  361.                     w.left.color = RBNode.COLOR_BLACK;
  362.                     w.color = RBNode.COLOR_RED;
  363.                     this.rightRotate( w);
  364.                     w = x.parent.right;
  365.                 }
  366.                 w.color = x.parent.color;
  367.                 x.parent.color = RBNode.COLOR_BLACK;
  368.                 w.right.color = RBNode.COLOR_BLACK;
  369.                 this.leftRotate( x.parent);
  370.                 x = root;
  371.             }
  372.         }
  373.         else{
  374.             w = x.parent.left;
  375.             if(w.color === RBNode.COLOR_RED){
  376.                 w.color = RBNode.COLOR_BLACK;
  377.                 x.parent.color = RBNode.COLOR_RED;
  378.                 this.rightRotate( x.parent);
  379.                 w = x.parent.left;
  380.             }
  381.             if( w.right.color === RBNode.COLOR_BLACK &&
  382.                 w.left.color === RBNode.COLOR_BLACK){
  383.  
  384.                 w.color = RBNode.COLOR_RED;
  385.                 x = x.parent;
  386.             }
  387.             else{
  388.                 if ( w.left.color === RBNode.COLOR_BLACK){
  389.                     w.right.color = RBNode.COLOR_BLACK;
  390.                     w.color = RBNode.COLOR_RED;
  391.                     this.leftRotate( w);
  392.                     w = x.parent.left;
  393.                 }
  394.                 w.color = x.parent.color;
  395.                 x.parent.color = RBNode.COLOR_BLACK;
  396.                 w.left.color = RBNode.COLOR_BLACK;
  397.                 this.rightRotate(x.parent);
  398.                 x = root;
  399.             }
  400.         }
  401.     }
  402.     x.color = RBNode.COLOR_BLACK;
  403.     if ( this.nil.color !== RBNode.COLOR_BLACK){
  404.         throw new Exception("Invalid colors");
  405.     }
  406. };
  407.  
  408.  
  409. function RBNode (_key, _value) {
  410.     this.color = RBNode.COLOR_BLACK;
  411.     this.key = _key;
  412.     this.value = _value;
  413.     this.left = null;
  414.     this.right = null;
  415.     this.parent = null;
  416. }
  417.  
  418. RBNode.prototype.toString = function() {
  419.     return "{ key:" + this.key.toString() + "," +
  420.         "value:" + this.value.toString() +  "}";
  421. };
  422.  
  423. RBNode.COLOR_BLACK = 0;
  424. RBNode.COLOR_RED = 1;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement