1 var define = require("../define").define, 2 Tree = require("./Tree"), 3 base = require("../base"), 4 multiply = base.string.multiply; 5 6 var RED = "red", BLACK = "black"; 7 8 var isRed = function(node) { 9 return node != null && node.red; 10 }; 11 12 var makeNode = function(data, parent) { 13 return { 14 data : data, 15 red : true, 16 left : null, 17 right : null 18 } 19 }; 20 21 var insert = function(root, data, compare) { 22 if (root == null) { 23 return makeNode(data, null); 24 25 } else { 26 var cmp = compare(data, root.data); 27 if (cmp) { 28 var dir = cmp == -1 ? "left" : "right"; 29 var otherDir = dir == "left" ? "right" : "left"; 30 root[dir] = insert(root[dir], data, compare); 31 var node = root[dir]; 32 33 if (isRed(node)) { 34 35 var sibling = root[otherDir]; 36 if (isRed(sibling)) { 37 /* Case 1 */ 38 root.red = true; 39 node.red = false; 40 sibling.red = false; 41 } else { 42 43 if (isRed(node[dir])) { 44 45 root = rotateSingle(root, otherDir); 46 } else if (isRed(node[otherDir])) { 47 48 root = rotateDouble(root, otherDir); 49 } 50 } 51 52 } 53 } 54 } 55 return root; 56 }; 57 58 var rotateSingle = function(root, dir) { 59 var otherDir = dir == "left" ? "right" : "left"; 60 var save = root[otherDir]; 61 root[otherDir] = save[dir]; 62 save[dir] = root; 63 root.red = true; 64 save.red = false; 65 return save; 66 }; 67 68 var rotateDouble = function(root, dir) { 69 var otherDir = dir == "left" ? "right" : "left"; 70 root[otherDir] = rotateSingle(root[otherDir], otherDir); 71 return rotateSingle(root, dir); 72 }; 73 74 75 var remove = function (root, data, done, compare) { 76 if (root == null) { 77 done.done = true; 78 } else { 79 var dir; 80 if (compare(data, root.data) == 0) { 81 if (root.left == null || root.right == null) { 82 var save = root[root.left == null ? "right" : "left"]; 83 /* Case 0 */ 84 if (isRed(root)) { 85 done.done = true; 86 } else if (isRed(save)) { 87 save.red = false; 88 done.done = true; 89 } 90 return save; 91 } 92 else { 93 var heir = root.right, p; 94 while (heir.left != null) { 95 p = heir; 96 heir = heir.left; 97 } 98 p && (p.left = null); 99 root.data = heir.data; 100 data = heir.data; 101 } 102 } 103 dir = compare(data, root.data) == -1 ? "left" : "right"; 104 root[dir] = remove(root[dir], data, done, compare); 105 !done.done && (root = removeBalance(root, dir, done)); 106 } 107 return root; 108 }; 109 110 var removeBalance = function(root, dir, done) { 111 var notDir = dir == "left" ? "right" : "left"; 112 var p = root, s = p[notDir]; 113 if (isRed(s)) { 114 root = rotateSingle(root, dir); 115 s = p[notDir]; 116 } 117 if (s != null) { 118 if (!isRed(s.left) && !isRed(s.right)) { 119 isRed(p) && (done.done = true); 120 p.red = 0; 121 s.red = 1; 122 } else { 123 var save = p.red, newRoot = ( root === p ); 124 p = (isRed(s[notDir]) ? rotateSingle : rotateDouble)(p, dir); 125 p.red = save; 126 p.left.red = p.right.red = 0; 127 if (newRoot) { 128 root = p; 129 } else { 130 root[dir] = p; 131 } 132 done.done = true; 133 } 134 } 135 return root; 136 }; 137 var RedBlackTree; 138 /** 139 * @class <p>A RedBlack tree is a form of a self balancing binary tree.</p> 140 * 141 * <b>Performance</b> 142 * <table> 143 * <tr><td></td><td>Best</td><td>Worst</td></tr> 144 * <tr><td>Space</td><td>O(n)</td><td>O(n)</td></tr> 145 * <tr><td>Search</td><td>O(log n)</td><td>O(log n)</td></tr> 146 * <tr><td>Insert</td><td>O(log n)</td><td>O(log n)</td></tr> 147 * <tr><td>Delete</td><td>O(log n)</td><td>O(log n)</td></tr> 148 * <table> 149 * @name RedBlackTree 150 * @augments comb.collections.Tree 151 * @memberOf comb.collections 152 */ 153 module.exports = exports = define(Tree, { 154 instance : { 155 /**@lends comb.collections.RedBlackTree.prototype*/ 156 insert : function(data) { 157 this.__root = insert(this.__root, data, this.compare); 158 this.__root.red = false; 159 }, 160 161 remove : function(data) { 162 var done = {done : false}; 163 var root = remove(this.__root, data, done, this.compare); 164 if (root != null) 165 root.red = 0; 166 this.__root = root; 167 }, 168 169 170 __printNode : function(node, level) { 171 var str = []; 172 if (node == null || node == undefined) { 173 str.push(multiply('\t', level)); 174 str.push("~"); 175 console.log(str.join("")); 176 } else { 177 this.__printNode(node.right, level + 1); 178 str.push(multiply('\t', level)); 179 str.push((node.red ? "RED" : "BLACK") + ":" + node.data + "\n"); 180 console.log(str.join("")); 181 this.__printNode(node.left, level + 1); 182 } 183 } 184 185 } 186 }); 187 188