(function () { "use strict"; function defineLeafy(_) { function compare(a, b) { var ret = 0; if (a > b) { return 1; } else if (a < b) { return -1; } else if (!b) { return 1; } return ret; } var multiply = _.multiply; var Tree = _.declare({ instance: { /** * Prints a node * @param node node to print * @param level the current level the node is at, Used for formatting */ __printNode: function (node, level) { //console.log(level); var str = []; if (_.isUndefinedOrNull(node)) { str.push(multiply('\t', level)); str.push("~"); console.log(str.join("")); } else { this.__printNode(node.right, level + 1); str.push(multiply('\t', level)); str.push(node.data + "\n"); console.log(str.join("")); this.__printNode(node.left, level + 1); } }, constructor: function (options) { options = options || {}; this.compare = options.compare || compare; this.__root = null; }, insert: function () { throw new Error("Not Implemented"); }, remove: function () { throw new Error("Not Implemented"); }, clear: function () { this.__root = null; }, isEmpty: function () { return !(this.__root); }, traverseWithCondition: function (node, order, callback) { var cont = true; if (node) { order = order || Tree.PRE_ORDER; if (order === Tree.PRE_ORDER) { cont = callback(node.data); if (cont) { cont = this.traverseWithCondition(node.left, order, callback); if (cont) { cont = this.traverseWithCondition(node.right, order, callback); } } } else if (order === Tree.IN_ORDER) { cont = this.traverseWithCondition(node.left, order, callback); if (cont) { cont = callback(node.data); if (cont) { cont = this.traverseWithCondition(node.right, order, callback); } } } else if (order === Tree.POST_ORDER) { cont = this.traverseWithCondition(node.left, order, callback); if (cont) { if (cont) { cont = this.traverseWithCondition(node.right, order, callback); } if (cont) { cont = callback(node.data); } } } else if (order === Tree.REVERSE_ORDER) { cont = this.traverseWithCondition(node.right, order, callback); if (cont) { cont = callback(node.data); if (cont) { cont = this.traverseWithCondition(node.left, order, callback); } } } } return cont; }, traverse: function (node, order, callback) { if (node) { order = order || Tree.PRE_ORDER; if (order === Tree.PRE_ORDER) { callback(node.data); this.traverse(node.left, order, callback); this.traverse(node.right, order, callback); } else if (order === Tree.IN_ORDER) { this.traverse(node.left, order, callback); callback(node.data); this.traverse(node.right, order, callback); } else if (order === Tree.POST_ORDER) { this.traverse(node.left, order, callback); this.traverse(node.right, order, callback); callback(node.data); } else if (order === Tree.REVERSE_ORDER) { this.traverse(node.right, order, callback); callback(node.data); this.traverse(node.left, order, callback); } } }, forEach: function (cb, scope, order) { if (typeof cb !== "function") { throw new TypeError(); } order = order || Tree.IN_ORDER; scope = scope || this; this.traverse(this.__root, order, function (node) { cb.call(scope, node, this); }); }, map: function (cb, scope, order) { if (typeof cb !== "function") { throw new TypeError(); } order = order || Tree.IN_ORDER; scope = scope || this; var ret = new this._static(); this.traverse(this.__root, order, function (node) { ret.insert(cb.call(scope, node, this)); }); return ret; }, filter: function (cb, scope, order) { if (typeof cb !== "function") { throw new TypeError(); } order = order || Tree.IN_ORDER; scope = scope || this; var ret = new this._static(); this.traverse(this.__root, order, function (node) { if (cb.call(scope, node, this)) { ret.insert(node); } }); return ret; }, reduce: function (fun, accumulator, order) { var arr = this.toArray(order); var args = [arr, fun]; if (!_.isUndefinedOrNull(accumulator)) { args.push(accumulator); } return _.reduce.apply(_, args); }, reduceRight: function (fun, accumulator, order) { var arr = this.toArray(order); var args = [arr, fun]; if (!_.isUndefinedOrNull(accumulator)) { args.push(accumulator); } return _.reduceRight.apply(_, args); }, every: function (cb, scope, order) { if (typeof cb !== "function") { throw new TypeError(); } order = order || Tree.IN_ORDER; scope = scope || this; var ret = false; this.traverseWithCondition(this.__root, order, function (node) { ret = cb.call(scope, node, this); return ret; }); return ret; }, some: function (cb, scope, order) { if (typeof cb !== "function") { throw new TypeError(); } order = order || Tree.IN_ORDER; scope = scope || this; var ret; this.traverseWithCondition(this.__root, order, function (node) { ret = cb.call(scope, node, this); return !ret; }); return ret; }, toArray: function (order) { order = order || Tree.IN_ORDER; var arr = []; this.traverse(this.__root, order, function (node) { arr.push(node); }); return arr; }, contains: function (value) { var ret = false; var root = this.__root; while (root !== null) { var cmp = this.compare(value, root.data); if (cmp) { root = root[(cmp === -1) ? "left" : "right"]; } else { ret = true; root = null; } } return ret; }, find: function (value) { var ret; var root = this.__root; while (root) { var cmp = this.compare(value, root.data); if (cmp) { root = root[(cmp === -1) ? "left" : "right"]; } else { ret = root.data; break; } } return ret; }, findLessThan: function (value, exclusive) { //find a better way!!!! var ret = [], compare = this.compare; this.traverseWithCondition(this.__root, Tree.IN_ORDER, function (v) { var cmp = compare(value, v); if ((!exclusive && cmp === 0) || cmp === 1) { ret.push(v); return true; } else { return false; } }); return ret; }, findGreaterThan: function (value, exclusive) { //find a better way!!!! var ret = [], compare = this.compare; this.traverse(this.__root, Tree.REVERSE_ORDER, function (v) { var cmp = compare(value, v); if ((!exclusive && cmp === 0) || cmp === -1) { ret.push(v); return true; } else { return false; } }); return ret; }, print: function () { this.__printNode(this.__root, 0); } }, "static": { PRE_ORDER: "pre_order", IN_ORDER: "in_order", POST_ORDER: "post_order", REVERSE_ORDER: "reverse_order" } }); var AVLTree = (function () { var abs = Math.abs; var makeNode = function (data) { return { data: data, balance: 0, left: null, right: null }; }; var rotateSingle = function (root, dir, otherDir) { var save = root[otherDir]; root[otherDir] = save[dir]; save[dir] = root; return save; }; var rotateDouble = function (root, dir, otherDir) { root[otherDir] = rotateSingle(root[otherDir], otherDir, dir); return rotateSingle(root, dir, otherDir); }; var adjustBalance = function (root, dir, bal) { var otherDir = dir === "left" ? "right" : "left"; var n = root[dir], nn = n[otherDir]; if (nn.balance === 0) { root.balance = n.balance = 0; } else if (nn.balance === bal) { root.balance = -bal; n.balance = 0; } else { /* nn.balance == -bal */ root.balance = 0; n.balance = bal; } nn.balance = 0; }; var insertAdjustBalance = function (root, dir) { var otherDir = dir === "left" ? "right" : "left"; var n = root[dir]; var bal = dir === "right" ? -1 : +1; if (n.balance === bal) { root.balance = n.balance = 0; root = rotateSingle(root, otherDir, dir); } else { adjustBalance(root, dir, bal); root = rotateDouble(root, otherDir, dir); } return root; }; var removeAdjustBalance = function (root, dir, done) { var otherDir = dir === "left" ? "right" : "left"; var n = root[otherDir]; var bal = dir === "right" ? -1 : 1; if (n.balance === -bal) { root.balance = n.balance = 0; root = rotateSingle(root, dir, otherDir); } else if (n.balance === bal) { adjustBalance(root, otherDir, -bal); root = rotateDouble(root, dir, otherDir); } else { /* n.balance == 0 */ root.balance = -bal; n.balance = bal; root = rotateSingle(root, dir, otherDir); done.done = true; } return root; }; function insert(tree, data, cmp) { /* Empty tree case */ var root = tree.__root; if (root === null || root === undefined) { tree.__root = makeNode(data); } else { var it = root, upd = [], up = [], top = 0, dir; while (true) { dir = upd[top] = cmp(data, it.data) === -1 ? "left" : "right"; up[top++] = it; if (!it[dir]) { it[dir] = makeNode(data); break; } it = it[dir]; } if (!it[dir]) { return null; } while (--top >= 0) { up[top].balance += upd[top] === "right" ? -1 : 1; if (up[top].balance === 0) { break; } else if (abs(up[top].balance) > 1) { up[top] = insertAdjustBalance(up[top], upd[top]); if (top !== 0) { up[top - 1][upd[top - 1]] = up[top]; } else { tree.__root = up[0]; } break; } } } } function remove(tree, data, cmp) { var root = tree.__root; if (root !== null && root !== undefined) { var it = root, top = 0, up = [], upd = [], done = {done: false}, dir, compare; while (true) { if (!it) { return; } else if ((compare = cmp(data, it.data)) === 0) { break; } dir = upd[top] = compare === -1 ? "left" : "right"; up[top++] = it; it = it[dir]; } var l = it.left, r = it.right; if (!l || !r) { dir = !l ? "right" : "left"; if (top !== 0) { up[top - 1][upd[top - 1]] = it[dir]; } else { tree.__root = it[dir]; } } else { var heir = l; upd[top] = "left"; up[top++] = it; while (heir.right) { upd[top] = "right"; up[top++] = heir; heir = heir.right; } it.data = heir.data; up[top - 1][up[top - 1] === it ? "left" : "right"] = heir.left; } while (--top >= 0 && !done.done) { up[top].balance += upd[top] === "left" ? -1 : +1; if (abs(up[top].balance) === 1) { break; } else if (abs(up[top].balance) > 1) { up[top] = removeAdjustBalance(up[top], upd[top], done); if (top !== 0) { up[top - 1][upd[top - 1]] = up[top]; } else { tree.__root = up[0]; } } } } } return Tree.extend({ instance: { insert: function (data) { insert(this, data, this.compare); }, remove: function (data) { remove(this, data, this.compare); }, __printNode: function (node, level) { var str = []; if (!node) { str.push(multiply('\t', level)); str.push("~"); console.log(str.join("")); } else { this.__printNode(node.right, level + 1); str.push(multiply('\t', level)); str.push(node.data + ":" + node.balance + "\n"); console.log(str.join("")); this.__printNode(node.left, level + 1); } } } }); }()); var AnderssonTree = (function () { var nil = {level: 0, data: null}; function makeNode(data, level) { return { data: data, level: level, left: nil, right: nil }; } function skew(root) { if (root.level !== 0 && root.left.level === root.level) { var save = root.left; root.left = save.right; save.right = root; root = save; } return root; } function split(root) { if (root.level !== 0 && root.right.right.level === root.level) { var save = root.right; root.right = save.left; save.left = root; root = save; root.level++; } return root; } function insert(root, data, compare) { if (root === nil) { root = makeNode(data, 1); } else { var dir = compare(data, root.data) === -1 ? "left" : "right"; root[dir] = insert(root[dir], data, compare); root = skew(root); root = split(root); } return root; } var remove = function (root, data, compare) { var rLeft, rRight; if (root !== nil) { var cmp = compare(data, root.data); if (cmp === 0) { rLeft = root.left, rRight = root.right; if (rLeft !== nil && rRight !== nil) { var heir = rLeft; while (heir.right !== nil) { heir = heir.right; } root.data = heir.data; root.left = remove(rLeft, heir.data, compare); } else { root = root[rLeft === nil ? "right" : "left"]; } } else { var dir = cmp === -1 ? "left" : "right"; root[dir] = remove(root[dir], data, compare); } } if (root !== nil) { var rLevel = root.level; var rLeftLevel = root.left.level, rRightLevel = root.right.level; if (rLeftLevel < rLevel - 1 || rRightLevel < rLevel - 1) { if (rRightLevel > --root.level) { root.right.level = root.level; } root = skew(root); root = split(root); } } return root; }; return Tree.extend({ instance: { isEmpty: function () { return this.__root === nil || this._super(arguments); }, insert: function (data) { if (!this.__root) { this.__root = nil; } this.__root = insert(this.__root, data, this.compare); }, remove: function (data) { this.__root = remove(this.__root, data, this.compare); }, traverseWithCondition: function (node) { var cont = true; if (node !== nil) { return this._super(arguments); } return cont; }, traverse: function (node) { if (node !== nil) { this._super(arguments); } }, contains: function () { if (this.__root !== nil) { return this._super(arguments); } return false; }, __printNode: function (node, level) { var str = []; if (!node || !node.data) { str.push(multiply('\t', level)); str.push("~"); console.log(str.join("")); } else { this.__printNode(node.right, level + 1); str.push(multiply('\t', level)); str.push(node.data + ":" + node.level + "\n"); console.log(str.join("")); this.__printNode(node.left, level + 1); } } } }); }()); var BinaryTree = Tree.extend({ instance: { insert: function (data) { if (!this.__root) { this.__root = { data: data, parent: null, left: null, right: null }; return this.__root; } var compare = this.compare; var root = this.__root; while (root !== null) { var cmp = compare(data, root.data); if (cmp) { var leaf = (cmp === -1) ? "left" : "right"; var next = root[leaf]; if (!next) { return (root[leaf] = {data: data, parent: root, left: null, right: null}); } else { root = next; } } else { return; } } }, remove: function (data) { if (this.__root !== null) { var head = {right: this.__root}, it = head; var p, f = null; var dir = "right"; while (it[dir] !== null) { p = it; it = it[dir]; var cmp = this.compare(data, it.data); if (!cmp) { f = it; } dir = (cmp === -1 ? "left" : "right"); } if (f !== null) { f.data = it.data; p[p.right === it ? "right" : "left"] = it[it.left === null ? "right" : "left"]; } this.__root = head.right; } } } }); var RedBlackTree = (function () { var RED = "RED", BLACK = "BLACK"; var isRed = function (node) { return node !== null && node.red; }; var makeNode = function (data) { return { data: data, red: true, left: null, right: null }; }; var insert = function (root, data, compare) { if (!root) { return makeNode(data); } else { var cmp = compare(data, root.data); if (cmp) { var dir = cmp === -1 ? "left" : "right"; var otherDir = dir === "left" ? "right" : "left"; root[dir] = insert(root[dir], data, compare); var node = root[dir]; if (isRed(node)) { var sibling = root[otherDir]; if (isRed(sibling)) { /* Case 1 */ root.red = true; node.red = false; sibling.red = false; } else { if (isRed(node[dir])) { root = rotateSingle(root, otherDir); } else if (isRed(node[otherDir])) { root = rotateDouble(root, otherDir); } } } } } return root; }; var rotateSingle = function (root, dir) { var otherDir = dir === "left" ? "right" : "left"; var save = root[otherDir]; root[otherDir] = save[dir]; save[dir] = root; root.red = true; save.red = false; return save; }; var rotateDouble = function (root, dir) { var otherDir = dir === "left" ? "right" : "left"; root[otherDir] = rotateSingle(root[otherDir], otherDir); return rotateSingle(root, dir); }; var remove = function (root, data, done, compare) { if (!root) { done.done = true; } else { var dir; if (compare(data, root.data) === 0) { if (!root.left || !root.right) { var save = root[!root.left ? "right" : "left"]; /* Case 0 */ if (isRed(root)) { done.done = true; } else if (isRed(save)) { save.red = false; done.done = true; } return save; } else { var heir = root.right, p; while (heir.left !== null) { p = heir; heir = heir.left; } if (p) { p.left = null; } root.data = heir.data; data = heir.data; } } dir = compare(data, root.data) === -1 ? "left" : "right"; root[dir] = remove(root[dir], data, done, compare); if (!done.done) { root = removeBalance(root, dir, done); } } return root; }; var removeBalance = function (root, dir, done) { var notDir = dir === "left" ? "right" : "left"; var p = root, s = p[notDir]; if (isRed(s)) { root = rotateSingle(root, dir); s = p[notDir]; } if (s !== null) { if (!isRed(s.left) && !isRed(s.right)) { if (isRed(p)) { done.done = true; } p.red = 0; s.red = 1; } else { var save = p.red, newRoot = ( root === p ); p = (isRed(s[notDir]) ? rotateSingle : rotateDouble)(p, dir); p.red = save; p.left.red = p.right.red = 0; if (newRoot) { root = p; } else { root[dir] = p; } done.done = true; } } return root; }; return Tree.extend({ instance: { insert: function (data) { this.__root = insert(this.__root, data, this.compare); this.__root.red = false; }, remove: function (data) { var done = {done: false}; var root = remove(this.__root, data, done, this.compare); if (root !== null) { root.red = 0; } this.__root = root; return data; }, __printNode: function (node, level) { var str = []; if (!node) { str.push(multiply('\t', level)); str.push("~"); console.log(str.join("")); } else { this.__printNode(node.right, level + 1); str.push(multiply('\t', level)); str.push((node.red ? RED : BLACK) + ":" + node.data + "\n"); console.log(str.join("")); this.__printNode(node.left, level + 1); } } } }); }()); return { Tree: Tree, AVLTree: AVLTree, AnderssonTree: AnderssonTree, BinaryTree: BinaryTree, RedBlackTree: RedBlackTree, IN_ORDER: Tree.IN_ORDER, PRE_ORDER: Tree.PRE_ORDER, POST_ORDER: Tree.POST_ORDER, REVERSE_ORDER: Tree.REVERSE_ORDER }; } if ("undefined" !== typeof exports) { if ("undefined" !== typeof module && module.exports) { module.exports = defineLeafy(require("extended")() .register("declare", require("declare.js")) .register(require("is-extended")) .register(require("array-extended")) .register(require("string-extended")) ); } } else if ("function" === typeof define) { define(["extended", "declare.js", "is-extended", "array-extended", "string-extended"], function (extended, declare, is, array, string) { return defineLeafy(extended() .register("declare", declare) .register(is) .register(array) .register(string) ); }); } else { this.leafy = defineLeafy(this.extended() .register("declare", this.declare) .register(this.isExtended) .register(this.arrayExtended) .register(this.stringExtended)); } }).call(this);