Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 1e5af370f1a9d14c9c89b233450b72a7609d2aa0 0 parents
@doug-martin authored
2  .gitignore
@@ -0,0 +1,2 @@
+.idea
+node_modules
74 .jshintrc
@@ -0,0 +1,74 @@
+{
+ "predef": [
+ "jasmine",
+ "spyOn",
+ "it",
+ "console",
+ "describe",
+ "expect",
+ "beforeEach",
+ "afterEach",
+ "waits",
+ "waitsFor",
+ "runs",
+ "$",
+ "jQuery",
+ "_",
+ "require",
+ "define",
+ "sinon",
+ "thumbs"
+ ],
+
+ "node" : true,
+ "browser" : true,
+ "devel" : true,
+ "jquery" : true,
+
+ "bitwise" : false,
+ "camelcase" : true,
+ "curly" : true,
+ "eqeqeq" : true,
+ "forin" : false,
+ "immed" : true,
+ "indent" : 4,
+ "latedef" : true,
+ "newcap" : true,
+ "noarg" : true,
+ "noempty" : true,
+ "nonew" : false,
+ "plusplus" : false,
+ "quotmark" : false,
+ "regexp" : false,
+ "undef" : true,
+ "unused" : false,
+ "strict" : false,
+ "trailing" : true,
+ "white" : false,
+
+ "asi" : false,
+ "boss" : false,
+ "debug" : false,
+ "eqnull" : true,
+ "es5" : true,
+ "esnext" : true,
+ "evil" : false,
+ "expr" : true,
+ "funcscope" : false,
+ "globalstrict" : false,
+ "iterator" : false,
+ "lastsemic" : false,
+ "laxbreak" : false,
+ "laxcomma" : false,
+ "loopfunc" : false,
+ "multistr" : false,
+ "onecase" : false,
+ "proto" : false,
+ "regexdash" : false,
+ "scripturl" : false,
+ "smarttabs" : false,
+ "shadow" : false,
+ "sub" : true,
+ "supernew" : true,
+ "validthis" : false
+}
4 .travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - 0.6
+ - 0.8
21 LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2013 Doug Martin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
263 README.md
@@ -0,0 +1,263 @@
+[![build status](https://secure.travis-ci.org/doug-martin/leafy.png)](http://travis-ci.org/doug-martin/leafy)
+
+[![browser support](http://ci.testling.com/doug-martin/leafy.png)](http://ci.testling.com/doug-martin/leafy)
+
+# Leafy
+
+`leafy` is a library of different tree implementations. `leafy` can be used in both the browser and node.
+
+Why would I need a tree in javascript? I have arrays and objects.
+
+Good question!
+
+The driving reason behind the creation of `leafy` was the library [`nools`](https://github.com/C2FO/nools) which needed a datastructure that was
+
+ * fast
+ * maintained order
+ * could have items inserted into it without having to re-sort the entire structure.
+
+This was needed in order to maintain a real time list of rule activations without having to search or sort the actions on insertion.
+
+Often a tree is overkill but when you need one its good to know its out there.
+
+## Installation
+
+```
+npm install leafy
+```
+
+Or [download the source](https://raw.github.com/doug-martin/leafy/master/index.js) ([minified](https://raw.github.com/doug-martin/leafy/master/leafy.min.js))
+
+**Note** `leafy` depends on [`declare.js`](https://github.com/doug-martin/declare.js), [`extended`](https://github.com/doug-martin/extended), [`is-extended`](https://github.com/doug-martin/is-extended), [`string-extended`](https://github.com/doug-martin/extended), and [`array-extended`](https://github.com/doug-martin/array-extended)
+
+
+## Usage
+
+`leafy` contains the following tree implementations.
+
+ * [`AVLTree`](http://en.wikipedia.org/wiki/AVL_tree)
+ * [`RedBlackTree`](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree)
+ * [`BinaryTree`](http://en.wikipedia.org/wiki/Binary_tree)
+ * [`AnderssonTree`](http://en.wikipedia.org/wiki/AA_tree)
+
+**`options`**
+
+When creating a tree you can specify a compare function used to sort items as they are inserted or removed.
+
+```javscript
+var tree = new leafy.AVLTree({
+ compare : function(a, b){
+ var ret = 0;
+ if (a.type > b.type) {
+ ret = 1;
+ } else if (a.type < b.type) {
+ ret = -1;
+ }
+ return ret;
+ }
+});
+```
+
+By default the tree uses a natural ordering function.
+
+```javascript
+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;
+}
+```
+
+Each tree contains the following functions.
+
+**`insert`**
+
+Insert an item into an the tree.
+
+```javascript
+tree.insert("a");
+tree.insert("b");
+tree.insert("c");
+tree.insert("aa");
+```
+
+**`remove`**
+
+Remove an item from a tree.
+
+```
+tree.remove("a");
+tree.remove("c");
+```
+
+**`clear`**
+
+Remove all items from a tree.
+
+```javascript
+
+tree.insert("a");
+tree.insert("b");
+tree.insert("c");
+tree.insert("aa");
+
+tree.clear();
+
+```
+
+**`isEmpty`**
+
+Returns a boolean indicating if the tree is currently empty.
+
+```
+tree.insert("a");
+tree.insert("b");
+tree.insert("c");
+tree.insert("aa");
+
+tree.isEmpty(); //false
+
+tree.clear();
+
+tree.isEmpty(); //true
+```
+
+**`contains`**
+
+Test if a tree contains a particular value.
+
+```javascript
+tree.insert("a");
+tree.insert("b");
+tree.insert("c");
+
+tree.contains("a"); //true
+tree.contains("d"); //false
+```
+
+**`toArray([order=leafy.IN_ORDER]);
+
+Coverts a tree to an array with the values in the order specified, or in order if not specified
+
+```javascript
+tree.insert("a");
+tree.insert("b");
+tree.insert("c");
+
+tree.toArray(); //["a", "b", "c", "d"]
+tree.toArray(leafy.REVERSE_ORDER); //["d", "c", "b", "a"]
+```
+
+**`forEach(iterator(iterator[, scope[, order=leafy.IN_ORDER]])`**
+
+Loop through the items in tree.
+
+By default the tree will loop through items in order.
+
+```javascript
+tree.insert("a");
+tree.insert("b");
+tree.insert("c");
+tree.insert("aa");
+
+tree.forEach(function(item, tree){
+ console.log(item); //"a", "b", "c", "d" respectively
+});
+```
+
+You can loop through a tree in any order you wish by specifying any of the following orders.
+
+* `leafy.REVERSE_ORDER`
+* `leafy.IN_ORDER`
+* `leafy.POST_ORDER`
+* `leafy.PRE_ORDER`
+
+```javascript
+
+tree.forEach(function(item, tree){
+ console.log(item); //"d", "c", "b", "a" respectively
+}, null, leafy.REVERSE_ORDER);
+
+```
+
+
+**`map(iterator[, scope[, order=leafy.IN_ORDER]])`**
+
+Map is very similar to the array counter part except that it returns new tree with the mapped values.
+
+```javascript
+//creates a new tree with the returned values "aa", "bb", "cc", "dd"
+var mapped = tree.map(function(item, tree){
+ return item + item;
+});
+
+```
+
+**`filter(iterator[, scope[, order=leafy.IN_ORDER]])`**
+
+Filter is very similar to the array counter part except that it returns new tree with the mapped values.
+
+```javascript
+//creates a new tree with the returned values "a", "b"
+var mapped = tree.map(function(item, tree){
+ return item === "a" || item === "b";
+});
+
+```
+
+### Other iterator methods.
+
+Trees also contains the following array methods that act just like their array counter part.
+
+**Note** all of these methods accept an order parameter.
+
+* `reduce`
+* `reduceRight`
+* `every`
+* `some`
+
+**`findLessThan(value[, exclusive=true])`**
+
+Find all values in a tree less than a particular value. If exclusive is set to false then the original value will be included in the resulting array.
+
+```javascript
+tree.insert("a");
+tree.insert("b");
+tree.insert("c");
+tree.insert("d");
+
+tree.findLessThan("d"); //["a", "b", "c"];
+tree.findLessThan("d", false); //["a", "b", "c", "d"];
+
+```
+
+**`findGreaterThan(value[, exclusive=true])`**
+
+Find all values in a tree greater than a particular value. If exclusive is set to false then the original value will be included in the resulting array.
+
+```javascript
+tree.insert("a");
+tree.insert("b");
+tree.insert("c");
+tree.insert("d");
+
+tree.findGreaterThan("a"); //["d", "c", "b"];
+tree.findGreaterThan("a", false); //["d", "c", "b", "a"];
+
+```
+
+**`print()`**
+
+Prints the current structure of a tree to the console.
+
+
+
+
+
+
56 grunt.js
@@ -0,0 +1,56 @@
+/*global module:false*/
+module.exports = function (grunt) {
+ var fs = require('fs');
+
+ // grunt doesn't natively support reading config from .jshintrc yet
+ var jshintOptions = JSON.parse(fs.readFileSync('./.jshintrc'));
+
+ // Project configuration.
+ grunt.initConfig({
+ pkg: '<json:package.json>',
+ meta: {
+ banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
+ '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
+ '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' +
+ '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;' +
+ ' Licensed <%= pkg.license %> */'
+ },
+
+ jshint: {
+ options: jshintOptions,
+ globals: jshintOptions.predef
+ },
+
+ lint: {
+ files: [
+ 'array.js'
+ ]
+ },
+
+ it: {
+ all: {
+ src: 'test/**/*.test.js',
+ options: {
+ timeout: 3000, // not fully supported yet
+ reporter: 'dot'
+ }
+ }
+ },
+ min: {
+ dist: {
+ src: ['<banner:meta.banner>', 'index.js'],
+ dest: '<%= pkg.name %>.min.js'
+ }
+ },
+ watch: {
+ files: '<config:lint.files>',
+ tasks: 'lint it'
+ },
+ uglify: {}
+ });
+
+ // Default task.
+ grunt.registerTask('default', 'lint it min');
+ grunt.loadNpmTasks('grunt-it');
+
+};
905 index.js
@@ -0,0 +1,905 @@
+(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.traverseWithCondition(node.right, order, callback);
+ callback(node.data);
+ this.traverseWithCondition(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) {
+ return (ret = cb.call(scope, node, this));
+ });
+ 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 === "left" ? -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 === "left" ? -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;
+ };
+
+ var insert = function (root, data, done, compare) {
+ if (root === null || root === undefined) {
+ root = makeNode(data);
+ } else {
+ var dir = compare(data, root.data) === -1 ? "left" : "right";
+ root[dir] = insert(root[dir], data, done, compare);
+
+ if (!done.done) {
+ /* Update balance factors */
+ root.balance += dir === "left" ? -1 : 1;
+ /* Rebalance as necessary and terminate */
+ if (root.balance === 0) {
+ done.done = true;
+ } else if (abs(root.balance) > 1) {
+ root = insertAdjustBalance(root, dir);
+ done.done = true;
+ }
+ }
+ }
+
+ return root;
+ };
+
+ var remove = function (root, data, done, compare) {
+ var dir, cmp, save, b;
+ if (root) {
+ //Remove node
+ cmp = compare(data, root.data);
+ if (cmp === 0) {
+ // Unlink and fix parent
+ var l = root.left, r = root.right;
+ if (!l || !r) {
+ dir = !l ? "right" : "left";
+ save = root[dir];
+ return save;
+ }
+ else {
+ var heir = l;
+ while ((r = heir.right) !== null) {
+ heir = r;
+ }
+ root.data = heir.data;
+ //reset and start searching
+ data = heir.data;
+ }
+ }
+ dir = compare(root.data, data) === -1 ? "right" : "left";
+ root[dir] = remove(root[dir], data, done, compare);
+ if (!done.done) {
+ /* Update balance factors */
+ b = (root.balance += (dir === "left" ? 1 : -1));
+ /* Terminate or rebalance as necessary */
+ var a = abs(b);
+ if (a === 1) {
+ done.done = true;
+ } else if (a > 1) {
+ root = removeAdjustBalance(root, dir, done);
+ }
+ }
+ }
+ return root;
+ };
+
+
+ return Tree.extend({
+ instance: {
+
+ insert: function (data) {
+ var done = {done: false};
+ this.__root = insert(this.__root, data, done, this.compare);
+ },
+
+
+ remove: function (data) {
+ this.__root = remove(this.__root, data, {done: false}, 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) {
+ return (this.__root = {
+ data: data,
+ parent: null,
+ left: null,
+ right: null
+ });
+ }
+ 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);
+
+
+
+
+
+
3  leafy.min.js
@@ -0,0 +1,3 @@
+/*! leafy - v0.0.1 - 2013-01-22
+* Copyright (c) 2013 Doug Martin; Licensed MIT */
+(function(){"use strict";function e(e){function t(e,t){var n=0;return e>t?1:e<t?-1:t?n:1}var n=e.multiply,r=e.declare({instance:{__printNode:function(t,r){var i=[];e.isUndefinedOrNull(t)?(i.push(n(" ",r)),i.push("~"),console.log(i.join(""))):(this.__printNode(t.right,r+1),i.push(n(" ",r)),i.push(t.data+"\n"),console.log(i.join("")),this.__printNode(t.left,r+1))},constructor:function(e){e=e||{},this.compare=e.compare||t,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(e,t,n){var i=!0;return e&&(t=t||r.PRE_ORDER,t===r.PRE_ORDER?(i=n(e.data),i&&(i=this.traverseWithCondition(e.left,t,n),i&&(i=this.traverseWithCondition(e.right,t,n)))):t===r.IN_ORDER?(i=this.traverseWithCondition(e.left,t,n),i&&(i=n(e.data),i&&(i=this.traverseWithCondition(e.right,t,n)))):t===r.POST_ORDER?(i=this.traverseWithCondition(e.left,t,n),i&&(i&&(i=this.traverseWithCondition(e.right,t,n)),i&&(i=n(e.data)))):t===r.REVERSE_ORDER&&(i=this.traverseWithCondition(e.right,t,n),i&&(i=n(e.data),i&&(i=this.traverseWithCondition(e.left,t,n))))),i},traverse:function(e,t,n){e&&(t=t||r.PRE_ORDER,t===r.PRE_ORDER?(n(e.data),this.traverse(e.left,t,n),this.traverse(e.right,t,n)):t===r.IN_ORDER?(this.traverse(e.left,t,n),n(e.data),this.traverse(e.right,t,n)):t===r.POST_ORDER?(this.traverse(e.left,t,n),this.traverse(e.right,t,n),n(e.data)):t===r.REVERSE_ORDER&&(this.traverseWithCondition(e.right,t,n),n(e.data),this.traverseWithCondition(e.left,t,n)))},forEach:function(e,t,n){if(typeof e!="function")throw new TypeError;n=n||r.IN_ORDER,t=t||this,this.traverse(this.__root,n,function(n){e.call(t,n,this)})},map:function(e,t,n){if(typeof e!="function")throw new TypeError;n=n||r.IN_ORDER,t=t||this;var i=new this._static;return this.traverse(this.__root,n,function(n){i.insert(e.call(t,n,this))}),i},filter:function(e,t,n){if(typeof e!="function")throw new TypeError;n=n||r.IN_ORDER,t=t||this;var i=new this._static;return this.traverse(this.__root,n,function(n){e.call(t,n,this)&&i.insert(n)}),i},reduce:function(t,n,r){var i=this.toArray(r),s=[i,t];return e.isUndefinedOrNull(n)||s.push(n),e.reduce.apply(e,s)},reduceRight:function(t,n,r){var i=this.toArray(r),s=[i,t];return e.isUndefinedOrNull(n)||s.push(n),e.reduceRight.apply(e,s)},every:function(e,t,n){if(typeof e!="function")throw new TypeError;n=n||r.IN_ORDER,t=t||this;var i=!1;return this.traverseWithCondition(this.__root,n,function(n){return i=e.call(t,n,this)}),i},some:function(e,t,n){if(typeof e!="function")throw new TypeError;n=n||r.IN_ORDER,t=t||this;var i;return this.traverseWithCondition(this.__root,n,function(n){return i=e.call(t,n,this),!i}),i},toArray:function(e){e=e||r.IN_ORDER;var t=[];return this.traverse(this.__root,e,function(e){t.push(e)}),t},contains:function(e){var t=!1,n=this.__root;while(n!==null){var r=this.compare(e,n.data);r?n=n[r===-1?"left":"right"]:(t=!0,n=null)}return t},find:function(e){var t,n=this.__root;while(n){var r=this.compare(e,n.data);if(!r){t=n.data;break}n=n[r===-1?"left":"right"]}return t},findLessThan:function(e,t){var n=[],i=this.compare;return this.traverseWithCondition(this.__root,r.IN_ORDER,function(r){var s=i(e,r);return!t&&s===0||s===1?(n.push(r),!0):!1}),n},findGreaterThan:function(e,t){var n=[],i=this.compare;return this.traverse(this.__root,r.REVERSE_ORDER,function(r){var s=i(e,r);return!t&&s===0||s===-1?(n.push(r),!0):!1}),n},print:function(){this.__printNode(this.__root,0)}},"static":{PRE_ORDER:"pre_order",IN_ORDER:"in_order",POST_ORDER:"post_order",REVERSE_ORDER:"reverse_order"}}),i=function(){var e=Math.abs,t=function(e){return{data:e,balance:0,left:null,right:null}},i=function(e,t,n){var r=e[n];return e[n]=r[t],r[t]=e,r},s=function(e,t,n){return e[n]=i(e[n],n,t),i(e,t,n)},o=function(e,t,n){var r=t==="left"?"right":"left",i=e[t],s=i[r];s.balance===0?e.balance=i.balance=0:s.balance===n?(e.balance=-n,i.balance=0):(e.balance=0,i.balance=n),s.balance=0},u=function(e,t){var n=t==="left"?"right":"left",r=e[t],u=t==="left"?-1:1;return r.balance===u?(e.balance=r.balance=0,e=i(e,n,t)):(o(e,t,u),e=s(e,n,t)),e},a=function(e,t,n){var r=t==="left"?"right":"left",u=e[r],a=t==="left"?-1:1;return u.balance===-a?(e.balance=u.balance=0,e=i(e,t,r)):u.balance===a?(o(e,r,-a),e=s(e,t,r)):(e.balance=-a,u.balance=a,e=i(e,t,r),n.done=!0),e},f=function(n,r,i,s){if(n===null||n===undefined)n=t(r);else{var o=s(r,n.data)===-1?"left":"right";n[o]=f(n[o],r,i,s),i.done||(n.balance+=o==="left"?-1:1,n.balance===0?i.done=!0:e(n.balance)>1&&(n=u(n,o),i.done=!0))}return n},l=function(t,n,r,i){var s,o,u,f;if(t){o=i(n,t.data);if(o===0){var c=t.left,h=t.right;if(!c||!h)return s=c?"left":"right",u=t[s],u;var p=c;while((h=p.right)!==null)p=h;t.data=p.data,n=p.data}s=i(t.data,n)===-1?"right":"left",t[s]=l(t[s],n,r,i);if(!r.done){f=t.balance+=s==="left"?1:-1;var d=e(f);d===1?r.done=!0:d>1&&(t=a(t,s,r))}}return t};return r.extend({instance:{insert:function(e){var t={done:!1};this.__root=f(this.__root,e,t,this.compare)},remove:function(e){this.__root=l(this.__root,e,{done:!1},this.compare)},__printNode:function(e,t){var r=[];e?(this.__printNode(e.right,t+1),r.push(n(" ",t)),r.push(e.data+":"+e.balance+"\n"),console.log(r.join("")),this.__printNode(e.left,t+1)):(r.push(n(" ",t)),r.push("~"),console.log(r.join("")))}}})}(),s=function(){function t(t,n){return{data:t,level:n,left:e,right:e}}function i(e){if(e.level!==0&&e.left.level===e.level){var t=e.left;e.left=t.right,t.right=e,e=t}return e}function s(e){if(e.level!==0&&e.right.right.level===e.level){var t=e.right;e.right=t.left,t.left=e,e=t,e.level++}return e}function o(n,r,u){if(n===e)n=t(r,1);else{var a=u(r,n.data)===-1?"left":"right";n[a]=o(n[a],r,u),n=i(n),n=s(n)}return n}var e={level:0,data:null},u=function(t,n,r){var o,a;if(t!==e){var f=r(n,t.data);if(f===0){o=t.left,a=t.right;if(o!==e&&a!==e){var l=o;while(l.right!==e)l=l.right;t.data=l.data,t.left=u(o,l.data,r)}else t=t[o===e?"right":"left"]}else{var c=f===-1?"left":"right";t[c]=u(t[c],n,r)}}if(t!==e){var h=t.level,p=t.left.level,d=t.right.level;if(p<h-1||d<h-1)d>--t.level&&(t.right.level=t.level),t=i(t),t=s(t)}return t};return r.extend({instance:{isEmpty:function(){return this.__root===e||this._super(arguments)},insert:function(t){this.__root||(this.__root=e),this.__root=o(this.__root,t,this.compare)},remove:function(e){this.__root=u(this.__root,e,this.compare)},traverseWithCondition:function(t){var n=!0;return t!==e?this._super(arguments):n},traverse:function(t){t!==e&&this._super(arguments)},contains:function(){return this.__root!==e?this._super(arguments):!1},__printNode:function(e,t){var r=[];!e||!e.data?(r.push(n(" ",t)),r.push("~"),console.log(r.join(""))):(this.__printNode(e.right,t+1),r.push(n(" ",t)),r.push(e.data+":"+e.level+"\n"),console.log(r.join("")),this.__printNode(e.left,t+1))}}})}(),o=r.extend({instance:{insert:function(e){if(!this.__root)return this.__root={data:e,parent:null,left:null,right:null};var t=this.compare,n=this.__root;while(n!==null){var r=t(e,n.data);if(!r)return;var i=r===-1?"left":"right",s=n[i];if(!s)return n[i]={data:e,parent:n,left:null,right:null};n=s}},remove:function(e){if(this.__root!==null){var t={right:this.__root},n=t,r,i=null,s="right";while(n[s]!==null){r=n,n=n[s];var o=this.compare(e,n.data);o||(i=n),s=o===-1?"left":"right"}i!==null&&(i.data=n.data,r[r.right===n?"right":"left"]=n[n.left===null?"right":"left"]),this.__root=t.right}}}}),u=function(){var e="RED",t="BLACK",i=function(e){return e!==null&&e.red},s=function(e){return{data:e,red:!0,left:null,right:null}},o=function(e,t,n){if(!e)return s(t);var r=n(t,e.data);if(r){var f=r===-1?"left":"right",l=f==="left"?"right":"left";e[f]=o(e[f],t,n);var c=e[f];if(i(c)){var h=e[l];i(h)?(e.red=!0,c.red=!1,h.red=!1):i(c[f])?e=u(e,l):i(c[l])&&(e=a(e,l))}}return e},u=function(e,t){var n=t==="left"?"right":"left",r=e[n];return e[n]=r[t],r[t]=e,e.red=!0,r.red=!1,r},a=function(e,t){var n=t==="left"?"right":"left";return e[n]=u(e[n],n),u(e,t)},f=function(e,t,n,r){if(!e)n.done=!0;else{var s;if(r(t,e.data)===0){if(!e.left||!e.right){var o=e[e.left?"left":"right"];return i(e)?n.done=!0:i(o)&&(o.red=!1,n.done=!0),o}var u=e.right,a;while(u.left!==null)a=u,u=u.left;a&&(a.left=null),e.data=u.data,t=u.data}s=r(t,e.data)===-1?"left":"right",e[s]=f(e[s],t,n,r),n.done||(e=l(e,s,n))}return e},l=function(e,t,n){var r=t==="left"?"right":"left",s=e,o=s[r];i(o)&&(e=u(e,t),o=s[r]);if(o!==null)if(!i(o.left)&&!i(o.right))i(s)&&(n.done=!0),s.red=0,o.red=1;else{var f=s.red,l=e===s;s=(i(o[r])?u:a)(s,t),s.red=f,s.left.red=s.right.red=0,l?e=s:e[t]=s,n.done=!0}return e};return r.extend({instance:{insert:function(e){this.__root=o(this.__root,e,this.compare),this.__root.red=!1},remove:function(e){var t={done:!1},n=f(this.__root,e,t,this.compare);n!==null&&(n.red=0),this.__root=n},__printNode:function(r,i){var s=[];r?(this.__printNode(r.right,i+1),s.push(n(" ",i)),s.push((r.red?e:t)+":"+r.data+"\n"),console.log(s.join("")),this.__printNode(r.left,i+1)):(s.push(n(" ",i)),s.push("~"),console.log(s.join("")))}}})}();return{Tree:r,AVLTree:i,AnderssonTree:s,BinaryTree:o,RedBlackTree:u}}"undefined"!=typeof exports?"undefined"!=typeof module&&module.exports&&(module.exports=e(require("extended")().register("declare",require("declare.js")).register(require("is-extended")).register(require("array-extended")).register(require("string-extended")))):"function"==typeof define?define(["extended","declare.js","is-extended","array-extended","string-extended"],function(t,n,r,i,s){return e(t().register("declare",n).register(r).register(i).register(s))}):this.leafy=e(this.extended().register("declare",this.declare).register(this.isExtended).register(this.arrayExtended).register(this.stringExtended))}).call(this);
44 package.json
@@ -0,0 +1,44 @@
+{
+ "name": "leafy",
+ "version": "0.0.1",
+ "description": "Different Tree Implementations",
+ "main": "index.js",
+ "scripts": {
+ "test": "it -r tap"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git:git@github.com:doug-martin/leafy.git"
+ },
+ "keywords": [
+ "DataStructures",
+ "Tree",
+ "AVL",
+ "AVL Tree",
+ "Red Black Tree",
+ "Andersson Tree"
+ ],
+ "testling": {
+ "files": "test/browserling.js",
+ "browsers": {
+ "ie": [6, 7, 8, 9],
+ "chrome": [4, 23, "canary"],
+ "firefox": [3, 3.5, 3.6, 4, 17, "nightly"],
+ "opera": [10, 10.5, 11, 11.5, 11.6, 12, "next"],
+ "safari": ["5.0.1", 5.1]
+ }
+ },
+ "author": "Doug Martin",
+ "license": "MIT",
+ "dependencies": {
+ "declare.js": "~0.0.3",
+ "extended": "~0.0.3",
+ "is-extended": "~0.0.3",
+ "array-extended": "~0.0.3",
+ "string-extended": "~0.0.3"
+ },
+ "devDependencies": {
+ "it": "~0.2.0",
+ "grunt-it": "~0.2.0"
+ }
+}
91 test/AVLTree.test.js
@@ -0,0 +1,91 @@
+"use strict";
+var it = require('it'),
+ leafy = require(".."),
+ helper = require("./treeTest.helper.js"),
+ Mammal = helper.Mammal,
+ AVLTree = leafy.AVLTree;
+
+
+it.describe("leafy.AVLTree",function (it) {
+
+ var words = ["c", "ca", "b", "ba", "bb", "a", "aa", "ab", "z", "d", "f", "h", "i", "ee", "ff", "hi", "j", "ajk"];
+ var wordsInOrder = [ 'a', 'aa', 'ab', 'ajk', 'b', 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z' ];
+ var wordsPreOrder = ['ba', 'aa', 'a', 'ajk', 'ab', 'b', 'h', 'd', 'c', 'bb', 'ca', 'f', 'ee', 'ff', 'i', 'hi', 'z', 'j'];
+ var wordsPostOrder = [ 'a', 'ab', 'b', 'ajk', 'aa', 'bb', 'ca', 'c', 'ee', 'ff', 'f', 'd', 'hi', 'j', 'z', 'i', 'h', 'ba'];
+
+
+ var mammals = [
+ new Mammal({type: "bird"}),
+ new Mammal({type: "dog"}),
+ new Mammal({type: "rat"}),
+ new Mammal({type: "zebra"}),
+ new Mammal({type: "mouse"}),
+ new Mammal({type: "horse"}),
+ new Mammal({type: "squirrel"}),
+ new Mammal({type: "groundhog"})
+ ],
+
+ mammalsInOrder = [
+ new Mammal({type: "bird"}),
+ new Mammal({type: "dog"}),
+ new Mammal({type: "groundhog"}),
+ new Mammal({type: "horse"}),
+ new Mammal({type: "mouse"}),
+ new Mammal({type: "rat"}),
+ new Mammal({type: "squirrel"}),
+ new Mammal({type: "zebra"})
+ ],
+
+ mammalsPreOrder = [
+ new Mammal({type: "mouse"}),
+ new Mammal({type: "dog"}),
+ new Mammal({type: "bird"}),
+ new Mammal({type: "horse"}),
+ new Mammal({type: "groundhog"}),
+ new Mammal({type: "squirrel"}),
+ new Mammal({type: "rat"}),
+ new Mammal({type: "zebra"})
+
+ ],
+
+ mammalsPostOrder = [
+ new Mammal({type: "bird"}),
+ new Mammal({type: "groundhog"}),
+ new Mammal({type: "horse"}),
+ new Mammal({type: "dog"}),
+ new Mammal({type: "rat"}),
+ new Mammal({type: "zebra"}),
+ new Mammal({type: "squirrel"}),
+ new Mammal({type: "mouse"})
+
+ ];
+ var orderedMammals = [
+ [AVLTree.IN_ORDER, mammalsInOrder],
+ [AVLTree.PRE_ORDER, mammalsPreOrder],
+ [AVLTree.POST_ORDER, mammalsPostOrder]
+ ]
+
+
+ var expectedOutput = "\t\t\t\t~\n\t\t\tz:-1\n\n\t\t\t\t\t~\n\t\t\t\tj:0\n\n\t\t\t\t\t~\n\t\ti:1\n\n\t\t\t\t~\n\t\t\t" +
+ "hi:0\n\n\t\t\t\t~\n\th:0\n\n\t\t\t\t\t~\n\t\t\t\tff:0\n\n\t\t\t\t\t~\n\t\t\tf:0\n\n\t\t\t\t\t~\n\t\t\t\t" +
+ "ee:0\n\n\t\t\t\t\t~\n\t\td:0\n\n\t\t\t\t\t~\n\t\t\t\tca:0\n\n\t\t\t\t\t~\n\t\t\tc:0\n\n\t\t\t\t\t~\n\t\t\t\t" +
+ "bb:0\n\n\t\t\t\t\t~\nba:1\n\n\t\t\t\t~\n\t\t\tb:0\n\n\t\t\t\t~\n\t\tajk:0\n\n\t\t\t\t~\n\t\t\tab:0\n\n\t\t\t\t~\n\t" +
+ "aa:1\n\n\t\t\t~\n\t\ta:0\n\n\t\t\t~";
+
+ var orderedWords = [
+ [AVLTree.IN_ORDER, wordsInOrder],
+ [AVLTree.PRE_ORDER, wordsPreOrder],
+ [AVLTree.POST_ORDER, wordsPostOrder]
+ ]
+
+
+ helper.setup(
+ it,
+ AVLTree,
+ words,
+ orderedWords,
+ mammals,
+ orderedMammals,
+ expectedOutput);
+
+}).as(module);
86 test/AnderssonTree.test.js
@@ -0,0 +1,86 @@
+"use strict";
+var it = require('it'),
+ leafy = require(".."),
+ helper = require("./treeTest.helper.js"),
+ Mammal = helper.Mammal,
+ AnderssonTree = leafy.AnderssonTree;
+
+
+it.describe("leafy.AnderssonTree", function (it) {
+ var words = ["c", "ca", "b", "ba", "bb", "a", "aa", "ab", "z", "d", "f", "h", "i", "ee", "ff", "hi", "j", "ajk"];
+ var wordsInOrder = [ 'a', 'aa', 'ab', 'ajk', 'b', 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z' ];
+ var wordsPreOrder = ['d', 'ba', 'aa', 'a', 'ajk', 'ab', 'b', 'c', 'bb', 'ca', 'h', 'f', 'ee', 'ff', 'i', 'hi', 'j', 'z'];
+ var wordsPostOrder = [ 'a', 'ab', 'b', 'ajk', 'aa', 'bb', 'ca', 'c', 'ba', 'ee', 'ff', 'f', 'hi', 'z', 'j', 'i', 'h', 'd'];
+
+
+
+
+ var mammals = [
+ new Mammal({type:"bird"}),
+ new Mammal({type:"dog"}),
+ new Mammal({type:"rat"}),
+ new Mammal({type:"zebra"}),
+ new Mammal({type:"mouse"}),
+ new Mammal({type:"horse"}),
+ new Mammal({type:"squirrel"}),
+ new Mammal({type:"groundhog"})
+ ],
+
+ mammalsInOrder = [
+ new Mammal({type:"bird"}),
+ new Mammal({type:"dog"}),
+ new Mammal({type:"groundhog"}),
+ new Mammal({type:"horse"}),
+ new Mammal({type:"mouse"}),
+ new Mammal({type:"rat"}),
+ new Mammal({type:"squirrel"}),
+ new Mammal({type:"zebra"})
+ ],
+
+ mammalsPreOrder = [
+ new Mammal({type:"horse"}),
+ new Mammal({type:"dog"}),
+ new Mammal({type:"bird"}),
+ new Mammal({type:"groundhog"}),
+ new Mammal({type:"rat"}),
+ new Mammal({type:"mouse"}),
+ new Mammal({type:"squirrel"}),
+ new Mammal({type:"zebra"})
+
+ ],
+
+ mammalsPostOrder = [
+ new Mammal({type:"bird"}),
+ new Mammal({type:"groundhog"}),
+ new Mammal({type:"dog"}),
+ new Mammal({type:"mouse"}),
+ new Mammal({type:"zebra"}),
+ new Mammal({type:"squirrel"}),
+ new Mammal({type:"rat"}),
+ new Mammal({type:"horse"})
+ ];
+ var orderedMammals = [
+ [AnderssonTree.IN_ORDER, mammalsInOrder],
+ [AnderssonTree.PRE_ORDER, mammalsPreOrder],
+ [AnderssonTree.POST_ORDER, mammalsPostOrder]
+ ]
+
+
+ var orderedWords = [
+ [AnderssonTree.IN_ORDER, wordsInOrder],
+ [AnderssonTree.PRE_ORDER, wordsPreOrder],
+ [AnderssonTree.POST_ORDER, wordsPostOrder]
+ ];
+ helper.setup(
+ it,
+ AnderssonTree,
+ words,
+ orderedWords,
+ mammals,
+ orderedMammals,
+ "\t\t\t\t\t~\n\t\t\t\tz:1\n\n\t\t\t\t\t~\n\t\t\tj:1\n\n\t\t\t\t~\n\t\ti:2\n\n\t\t\t\t~\n\t\t\thi:1\n\n\t\t\t\t" +
+ "~\n\th:3\n\n\t\t\t\t~\n\t\t\tff:1\n\n\t\t\t\t~\n\t\tf:2\n\n\t\t\t\t~\n\t\t\tee:1\n\n\t\t\t\t" +
+ "~\nd:4\n\n\t\t\t\t~\n\t\t\tca:1\n\n\t\t\t\t~\n\t\tc:2\n\n\t\t\t\t~\n\t\t\tbb:1\n\n\t\t\t\t" +
+ "~\n\tba:3\n\n\t\t\t\t\t~\n\t\t\t\tb:1\n\n\t\t\t\t\t~\n\t\t\tajk:2\n\n\t\t\t\t\t~\n\t\t\t\t" +
+ "ab:1\n\n\t\t\t\t\t~\n\t\taa:2\n\n\t\t\t\t~\n\t\t\ta:1\n\n\t\t\t\t~");
+}).as(module);
90 test/BinaryTree.test.js
@@ -0,0 +1,90 @@
+"use strict";
+var it = require('it'),
+ leafy = require(".."),
+ helper = require("./treeTest.helper.js"),
+ Mammal = helper.Mammal,
+ BinaryTree = leafy.BinaryTree;
+
+
+it.describe("leafy.BinaryTree", function (it) {
+
+ var words = ["c", "ca", "b", "ba", "bb", "a", "a", "aa", "ab", "z", "d", "f", "h", "i", "ee", "ff", "hi", "j", "ajk"];
+ var wordsInOrder = [ 'a', 'aa', 'ab', 'ajk', 'b', 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z' ];
+ var wordsPreOrder = ["c", "b", "a", "aa", "ab", "ajk", "ba", "bb", "ca", "z", "d", "f", "ee", "h", "ff", "i", "hi", "j"];
+ var wordsPostOrder = ["ajk", "ab", "aa", "a", "bb", "ba", "b", "ee", "ff", "hi", "j", "i", "h", "f", "d", "z", "ca", "c"];
+
+ var mammals = [
+ new Mammal({type:"bird"}),
+ new Mammal({type:"dog"}),
+ new Mammal({type:"rat"}),
+ new Mammal({type:"mouse"}),
+ new Mammal({type:"zebra"}),
+ new Mammal({type:"horse"}),
+ new Mammal({type:"squirrel"}),
+ new Mammal({type:"groundhog"})
+ ],
+
+ mammalsInOrder = [
+ new Mammal({type:"bird"}),
+ new Mammal({type:"dog"}),
+ new Mammal({type:"groundhog"}),
+ new Mammal({type:"horse"}),
+ new Mammal({type:"mouse"}),
+ new Mammal({type:"rat"}),
+ new Mammal({type:"squirrel"}),
+ new Mammal({type:"zebra"})
+ ],
+
+ mammalsPreOrder = [
+ new Mammal({type:"bird"}),
+ new Mammal({type:"dog"}),
+ new Mammal({type:"rat"}),
+ new Mammal({type:"mouse"}),
+ new Mammal({type:"horse"}),
+ new Mammal({type:"groundhog"}),
+ new Mammal({type:"zebra"}),
+ new Mammal({type:"squirrel"})
+ ],
+
+ mammalsPostOrder = [
+ new Mammal({type:"groundhog"}),
+ new Mammal({type:"horse"}),
+ new Mammal({type:"mouse"}),
+ new Mammal({type:"squirrel"}),
+ new Mammal({type:"zebra"}),
+ new Mammal({type:"rat"}),
+ new Mammal({type:"dog"}),
+ new Mammal({type:"bird"})
+ ];
+
+ var expectedOutput = "\t\t\t~\n\t\tz\n\n\t\t\t\t\t\t\t\t~\n\t\t\t\t\t\t\tj\n\n\t\t\t\t\t\t\t\t~\n\t\t\t\t\t\t" +
+ "i\n\n\t\t\t\t\t\t\t\t~\n\t\t\t\t\t\t\thi\n\n\t\t\t\t\t\t\t\t~\n\t\t\t\t\th\n\n\t\t\t\t\t\t\t~\n\t\t\t\t\t\t" +
+ "ff\n\n\t\t\t\t\t\t\t~\n\t\t\t\tf\n\n\t\t\t\t\t\t~\n\t\t\t\t\tee\n\n\t\t\t\t\t\t~\n\t\t\td\n\n\t\t\t\t~\n\t" +
+ "ca\n\n\t\t~\nc\n\n\t\t\t\t~\n\t\t\tbb\n\n\t\t\t\t~\n\t\tba\n\n\t\t\t~\n\tb\n\n\t\t\t\t\t\t~\n\t\t\t\t\t" +
+ "ajk\n\n\t\t\t\t\t\t~\n\t\t\t\tab\n\n\t\t\t\t\t~\n\t\t\taa\n\n\t\t\t\t~\n\t\ta\n\n\t\t\t~";
+ var orderedWords = [
+ [BinaryTree.IN_ORDER, wordsInOrder],
+ [BinaryTree.PRE_ORDER, wordsPreOrder],
+ [BinaryTree.POST_ORDER, wordsPostOrder]
+ ];
+ var orderedMammals = [
+ [BinaryTree.IN_ORDER, mammalsInOrder],
+ [BinaryTree.PRE_ORDER, mammalsPreOrder],
+ [BinaryTree.POST_ORDER, mammalsPostOrder]
+ ]
+
+
+ helper.setup(
+ it,
+ BinaryTree,
+ words,
+ orderedWords,
+ mammals,
+ orderedMammals,
+ expectedOutput);
+
+
+}).as(module);
+
+
+
88 test/RedBlackTree.test.js
@@ -0,0 +1,88 @@
+"use strict";
+var it = require('it'),
+ leafy = require(".."),
+ helper = require("./treeTest.helper.js"),
+ Mammal = helper.Mammal,
+ RedBlackTree = leafy.RedBlackTree;
+
+
+it.describe("leafy.RedBlackTree",function (it) {
+
+ var words = ["c", "ca", "b", "ba", "bb", "a", "aa", "ab", "z", "d", "f", "h", "i", "ee", "ff", "hi", "j", "ajk"];
+ var wordsInOrder = [ 'a', 'aa', 'ab', 'ajk', 'b', 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z' ];
+ var wordsPreOrder = ['d', 'ba', 'aa', 'a', 'ajk', 'ab', 'b', 'c', 'bb', 'ca', 'h', 'f', 'ee', 'ff', 'i', 'hi', 'z', 'j'];
+ var wordsPostOrder = [ 'a', 'ab', 'b', 'ajk', 'aa', 'bb', 'ca', 'c', 'ba', 'ee', 'ff', 'f', 'hi', 'j', 'z', 'i', 'h', 'd'];
+
+
+ var mammals = [
+ new Mammal({type: "bird"}),
+ new Mammal({type: "dog"}),
+ new Mammal({type: "rat"}),
+ new Mammal({type: "zebra"}),
+ new Mammal({type: "mouse"}),
+ new Mammal({type: "horse"}),
+ new Mammal({type: "squirrel"}),
+ new Mammal({type: "groundhog"})
+ ],
+
+ mammalsInOrder = [
+ new Mammal({type: "bird"}),
+ new Mammal({type: "dog"}),
+ new Mammal({type: "groundhog"}),
+ new Mammal({type: "horse"}),
+ new Mammal({type: "mouse"}),
+ new Mammal({type: "rat"}),
+ new Mammal({type: "squirrel"}),
+ new Mammal({type: "zebra"})
+ ],
+
+ mammalsPreOrder = [
+ new Mammal({type: "dog"}),
+ new Mammal({type: "bird"}),
+ new Mammal({type: "rat"}),
+ new Mammal({type: "horse"}),
+ new Mammal({type: "groundhog"}),
+ new Mammal({type: "mouse"}),
+ new Mammal({type: "zebra"}),
+ new Mammal({type: "squirrel"})
+ ],
+
+ mammalsPostOrder = [
+ new Mammal({type: "bird"}),
+ new Mammal({type: "groundhog"}),
+ new Mammal({type: "mouse"}),
+ new Mammal({type: "horse"}),
+ new Mammal({type: "squirrel"}),
+ new Mammal({type: "zebra"}),
+ new Mammal({type: "rat"}),
+ new Mammal({type: "dog"})
+ ];
+
+ var orderedMammals = [
+ [RedBlackTree.IN_ORDER, mammalsInOrder],
+ [RedBlackTree.PRE_ORDER, mammalsPreOrder],
+ [RedBlackTree.POST_ORDER, mammalsPostOrder]
+ ];
+
+ var expectedOutput = "\t\t\t\t~\n\t\t\tBLACK:z\n\n\t\t\t\t\t~\n\t\t\t\tRED:j\n\n\t\t\t\t\t~\n\t\tBLACK:i" +
+ "\n\n\t\t\t\t~\n\t\t\tBLACK:hi\n\n\t\t\t\t~\n\tBLACK:h\n\n\t\t\t\t~\n\t\t\tBLACK:ff\n\n\t\t\t\t~" +
+ "\n\t\tBLACK:f\n\n\t\t\t\t~\n\t\t\tBLACK:ee\n\n\t\t\t\t~\nBLACK:d\n\n\t\t\t\t~\n\t\t\tBLACK:ca" +
+ "\n\n\t\t\t\t~\n\t\tBLACK:c\n\n\t\t\t\t~\n\t\t\tBLACK:bb\n\n\t\t\t\t~\n\tBLACK:ba" +
+ "\n\n\t\t\t\t\t~\n\t\t\t\tRED:b\n\n\t\t\t\t\t~\n\t\t\tBLACK:ajk\n\n\t\t\t\t\t~\n\t\t\t\t" +
+ "RED:ab\n\n\t\t\t\t\t~\n\t\tBLACK:aa\n\n\t\t\t\t~\n\t\t\tBLACK:a\n\n\t\t\t\t~";
+ var orderedWords = [
+ [RedBlackTree.IN_ORDER, wordsInOrder],
+ [RedBlackTree.PRE_ORDER, wordsPreOrder],
+ [RedBlackTree.POST_ORDER, wordsPostOrder]
+ ];
+
+ helper.setup(
+ it,
+ RedBlackTree,
+ words,
+ orderedWords,
+ mammals,
+ orderedMammals,
+ expectedOutput);
+
+}).as(module);
24 test/Tree.test.js
@@ -0,0 +1,24 @@
+"use strict";
+var it = require('it'),
+ assert = require('assert'),
+ array = require("array-extended"),
+ leafy = require(".."),
+ Tree = leafy.Tree;
+
+
+it.describe("leafy.Tree",function (it) {
+ var methods = ["insert", "remove"];
+
+ var tree = new Tree();
+ array(methods).forEach(function (m) {
+ it.describe("#" + m, function (it) {
+ it.should("be abstract", function () {
+ assert.throws(function () {
+ tree[m]();
+ });
+ });
+ });
+ });
+
+}).as(module);
+
12 test/browserling.js
@@ -0,0 +1,12 @@
+var it = require("it");
+
+it.reporter("tap");
+
+require("./AnderssonTree.test");
+require("./AVLTree.test");
+require("./BinaryTree.test");
+require("./RedBlackTree.test");
+require("./Tree.test");
+
+
+it.run();
339 test/treeTest.helper.js
@@ -0,0 +1,339 @@
+"use strict";
+var assert = require('assert'),
+ declare = require("declare.js"),
+ array = require("array-extended"),
+ is = require("is-extended");
+
+var Mammal = declare({
+ instance: {
+
+ constructor: function (options) {
+ options = options || {};
+ this._super(arguments);
+ this._type = options.type || "mammal";
+ },
+
+ toString: function () {
+ return this.get("type");
+ },
+
+ //Define your getters
+ getters: {
+ type: function () {
+ return this._type;
+ }
+ }
+ },
+
+ //Define your static methods
+ "static": {
+ compare: function (a, b) {
+ var ret = 0;
+ if (a.get("type") > b.get("type")) {
+ ret = 1;
+ } else if (a.get("type") < b.get("type")) {
+ ret = -1;
+ }
+ return ret;
+ }
+ }
+}).as(exports, "Mammal");
+
+exports.setup = function (it, Tree, words, orderedWords, mammals, orderedMammals, expectedPrint) {
+ it.describe("inserting strings", function (it) {
+
+ var ordered = orderedWords;
+
+ var tree = new Tree();
+ array(words).forEach(function (word) {
+ tree.insert(word);
+ });
+
+ it.should("find values", function () {
+ assert.deepEqual(tree.find("a"), "a");
+ assert.isUndefined(tree.find("askjjbfiashf"));
+ });
+
+ it.should("find values less than the value", function () {
+ assert.deepEqual(tree.findLessThan("a", true), []);
+ assert.deepEqual(tree.findLessThan("b", true), ["a", "aa", "ab", "ajk"]);
+ assert.deepEqual(tree.findLessThan("c", true), ["a", "aa", "ab", "ajk", "b", "ba", "bb"]);
+ assert.deepEqual(tree.findLessThan("ca", true), ["a", "aa", "ab", "ajk", "b", "ba", "bb", "c"]);
+ });
+ it.should("find values less or equal to the value", function () {
+ assert.deepEqual(tree.findLessThan("a"), ["a"]);
+ assert.deepEqual(tree.findLessThan("b"), ["a", "aa", "ab", "ajk", "b"]);
+ assert.deepEqual(tree.findLessThan("c"), ["a", "aa", "ab", "ajk", "b", "ba", "bb", "c"]);
+ assert.deepEqual(tree.findLessThan("ca"), ["a", "aa", "ab", "ajk", "b", "ba", "bb", "c", "ca"]);
+ });
+ it.should("find values greater than equal to the value", function () {
+ assert.deepEqual(tree.findGreaterThan("a"), ["a", 'aa', 'ab', 'ajk', 'b', 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z'].reverse());
+ assert.deepEqual(tree.findGreaterThan("b"), ["b", 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z'].reverse());
+ assert.deepEqual(tree.findGreaterThan("c"), ["c", 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z'].reverse());
+ assert.deepEqual(tree.findGreaterThan("ca"), ["ca", 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z'].reverse());
+ });
+ it.should("find values greater than the value", function () {
+ assert.deepEqual(tree.findGreaterThan("a", true), ['aa', 'ab', 'ajk', 'b', 'ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z'].reverse());
+ assert.deepEqual(tree.findGreaterThan("b", true), ['ba', 'bb', 'c', 'ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z'].reverse());
+ assert.deepEqual(tree.findGreaterThan("c", true), ['ca', 'd', 'ee', 'f', 'ff', 'h', 'hi', 'i', 'j', 'z'].reverse());
+ assert.deepEqual(tree.findGreaterThan("z", true), []);
+ });
+ it.should("contain those string", function () {
+ array(words).forEach(function (w) {
+ assert.isTrue(tree.contains(w));
+ });
+ });
+
+ it.describe("#toArray", function (it) {
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ assert.deepEqual(tree.toArray(order[0]), order[1]);
+ });
+ });
+ });
+ it.describe("#forEach", function (it) {
+
+ it.should("throw an error if cb is not defined", function () {
+ assert.throws(function () {
+ tree.forEach();
+ });
+ });
+
+
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ var i = 0;
+ tree.forEach(function (a) {
+ assert.deepEqual(a, order[1][i++]);
+ }, null, order[0]);
+ });
+ });
+ });
+
+ it.describe("#map", function (it) {
+
+ it.should("throw an error if cb is not defined", function () {
+ assert.throws(function () {
+ tree.map();
+ });
+ });
+
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ var i = 0, res = [];
+ tree.map(function (a) {
+ assert.deepEqual(a, order[1][i++]);
+ res.push(a);
+ return a;
+ }, null, order[0]);
+ });
+ });
+ });
+
+ it.describe("#filter", function (it) {
+
+ it.should("throw an error if cb is not defined", function () {
+ assert.throws(function () {
+ tree.filter();
+ });
+ });
+
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ var i = 0;
+ assert.isTrue(tree.filter(
+ function (a) {
+ assert.deepEqual(a, order[1][i++]);
+ return false;
+ }, null, order[0]).isEmpty());
+ });
+ });
+ });
+
+ it.describe("#reduce", function (it) {
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ assert.equal(tree.reduce(function (a, b) {
+ return a + b;
+ }, null, order[0]), order[1].join(""));
+ });
+ });
+
+ array(ordered).forEach(function (order) {
+ it.should(order[0] + "-accumulator", function () {
+ assert.equal(tree.reduce(function (a, b) {
+ return a + b;
+ }, [], order[0]), order[1].join(""));
+ });
+ });
+ });
+
+
+ it.describe("#reduceRight", function (it) {
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ assert.equal(tree.reduceRight(function (a, b) {
+ return a + b;
+ }, null, order[0]), order[1].slice().reverse().join(""));
+ });
+ });
+ });
+
+
+ it.describe("#every", function (it) {
+
+ it.should("throw an error if no cb is supplied", function () {
+ assert.throws(function () {
+ tree.every();
+ });
+ });
+
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ var i = 0;
+ assert.isTrue(tree.every(function (a) {
+ assert.deepEqual(a, order[1][i++]);
+ return is.isString(a);
+ }, null, order[0]));
+ i = 0;
+ assert.isFalse(tree.every(function (a) {
+ assert.deepEqual(a, order[1][i++]);
+ return is.isNumber(a);
+ }, null, order[0]));
+ });
+ });
+ });
+
+ it.describe("#some", function (it) {
+
+ it.should("throw an error if no cb is supplied", function () {
+ assert.throws(function () {
+ tree.some();
+ });
+ });
+
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ var i = 0;
+ assert.isTrue(tree.some(function (a) {
+ assert.deepEqual(a, order[1][i++]);
+ return is.isString(a);
+ }, null, order[0]));
+ i = 0;
+ assert.isFalse(tree.some(function (a) {
+ assert.deepEqual(a, order[1][i++]);
+ return is.isNumber(a);
+ }, null, order[0]));
+ });
+ });
+ });
+
+ it.should("print the tree correctly", function () {
+ var expected = expectedPrint;
+ var res = [];
+ var orig = console.log;
+ console.log = function (str) {
+ res.push(str);
+ };
+ tree.print();
+ console.log = orig;
+ assert.equal(res.join("\n"), expected);
+ });
+ it.should("delete a string ", function () {
+ array(words).forEach(function (word) {
+ tree.remove(word);
+ });
+ array(words).forEach(function (w) {
+ assert.isFalse(tree.contains(w));
+ });
+ assert.isTrue(tree.isEmpty());
+ });
+ it.should("clear", function () {
+ array(words).forEach(function (word) {
+ tree.insert(word);
+ });
+ tree.clear();
+ });
+ });
+
+ it.describe("inserting objects with comparator", function (it) {
+
+//Super of other classes
+
+
+ var ordered = orderedMammals;
+ var tree = new Tree({
+ compare: Mammal.compare
+ });
+ array(mammals).forEach(function (mammal) {
+ tree.insert(mammal);
+ });
+ it.should("contain those objects", function () {
+ assert.isTrue(array.every(mammals, function (mammal) {
+ return tree.contains(mammal);
+ }));
+ });
+ it.describe("#toArray", function (it) {
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ assert.deepEqual(tree.toArray(order[0]), order[1]);
+ });
+ });
+ });
+ it.describe("#forEach", function (it) {
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ var i = 0;
+ tree.forEach(function (a) {
+ assert.deepEqual(a, order[1][i++]);
+ }, null, order[0]);
+ });
+ });
+ });
+
+ it.describe("#map", function (it) {
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ var i = 0;
+ tree.map(function (a) {
+ assert.deepEqual(a, order[1][i++]);
+ return a;
+ }, null, order[0]);
+ });
+ });
+ });
+
+ it.describe("#reduce", function (it) {
+ array(ordered).forEach(function (order) {
+ it.should(order[0], function () {
+ assert.equal(tree.reduce(function (a, b) {
+ return a + b;
+ }, null, order[0]), order[1].join(""));
+ });
+ });
+ });
+
+ it.should("#every", function () {
+ assert.isTrue(tree.every(function (a) {
+ return is.isString(a.get("type"));
+ }));
+ assert.isFalse(tree.every(function (a) {
+ return is.isNumber(a.get("type"));
+ }));
+
+ });
+ it.should("#some", function () {
+ assert.isTrue(tree.some(function (a) {
+ return a.get("type").match("a") !== null;
+ }));
+ assert.isFalse(tree.some(function (a) {
+ return a.get("type").match("1") !== null;
+ }));
+
+ });
+ });
+
+
+};
+
+
Please sign in to comment.
Something went wrong with that request. Please try again.