implemented deletion of elements & and iteration method & lots of tests
This commit is contained in:
parent
7b52111c31
commit
fe4564542b
@ -9,7 +9,7 @@ class N {
|
|||||||
this._left = null;
|
this._left = null;
|
||||||
this._right = null;
|
this._right = null;
|
||||||
this._parent = null;
|
this._parent = null;
|
||||||
if (val.id == null) {
|
if (val.id === null) {
|
||||||
throw new Error("You must define id!");
|
throw new Error("You must define id!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,6 +23,10 @@ class N {
|
|||||||
get parent () {
|
get parent () {
|
||||||
return this._parent;
|
return this._parent;
|
||||||
}
|
}
|
||||||
|
get sibling () {
|
||||||
|
return (this === this.parent.left) ?
|
||||||
|
this.parent.right : this.parent.left;
|
||||||
|
}
|
||||||
get left () {
|
get left () {
|
||||||
return this._left;
|
return this._left;
|
||||||
}
|
}
|
||||||
@ -30,13 +34,13 @@ class N {
|
|||||||
return this._right;
|
return this._right;
|
||||||
}
|
}
|
||||||
set left (n) {
|
set left (n) {
|
||||||
if (n != null) {
|
if (n !== null) {
|
||||||
n._parent = this;
|
n._parent = this;
|
||||||
}
|
}
|
||||||
this._left = n;
|
this._left = n;
|
||||||
}
|
}
|
||||||
set right (n) {
|
set right (n) {
|
||||||
if (n != null) {
|
if (n !== null) {
|
||||||
n._parent = this;
|
n._parent = this;
|
||||||
}
|
}
|
||||||
this._right = n;
|
this._right = n;
|
||||||
@ -47,7 +51,7 @@ class N {
|
|||||||
var newRight = this.right.left;
|
var newRight = this.right.left;
|
||||||
newParent.left = this;
|
newParent.left = this;
|
||||||
this.right = newRight;
|
this.right = newRight;
|
||||||
if (parent == null) {
|
if (parent === null) {
|
||||||
tree.root = newParent;
|
tree.root = newParent;
|
||||||
newParent._parent = null;
|
newParent._parent = null;
|
||||||
} else if (parent.left === this) {
|
} else if (parent.left === this) {
|
||||||
@ -58,13 +62,29 @@ class N {
|
|||||||
throw new Error("The elements are wrongly connected!");
|
throw new Error("The elements are wrongly connected!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
next () {
|
||||||
|
if ( this.right !== null ) {
|
||||||
|
// search the most left node in the right tree
|
||||||
|
var o = this.right;
|
||||||
|
while (o.left !== null) {
|
||||||
|
o = o.left;
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
} else {
|
||||||
|
var p = this;
|
||||||
|
while (p.parent !== null && p !== p.parent.left) {
|
||||||
|
p = p.parent;
|
||||||
|
}
|
||||||
|
return p.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
rotateRight (tree) {
|
rotateRight (tree) {
|
||||||
var parent = this.parent;
|
var parent = this.parent;
|
||||||
var newParent = this.left;
|
var newParent = this.left;
|
||||||
var newLeft = this.left.right;
|
var newLeft = this.left.right;
|
||||||
newParent.right = this;
|
newParent.right = this;
|
||||||
this.left = newLeft;
|
this.left = newLeft;
|
||||||
if (parent == null) {
|
if (parent === null) {
|
||||||
tree.root = newParent;
|
tree.root = newParent;
|
||||||
newParent._parent = null;
|
newParent._parent = null;
|
||||||
} else if (parent.left === this) {
|
} else if (parent.left === this) {
|
||||||
@ -89,13 +109,49 @@ class RBTree { //eslint-disable-line no-unused-vars
|
|||||||
constructor () {
|
constructor () {
|
||||||
this.root = null;
|
this.root = null;
|
||||||
}
|
}
|
||||||
find (id) {
|
findNodeWithLowerBound (from) {
|
||||||
var o = this.root;
|
var o = this.root;
|
||||||
if (o == null) {
|
if (o === null) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (o == null) {
|
if ((from === null || from < o.val.id) && o.left !== null) {
|
||||||
|
// o is included in the bound
|
||||||
|
// try to find an element that is closer to the bound
|
||||||
|
o = o.left;
|
||||||
|
} else if (o.val.id < from) {
|
||||||
|
// o is not within the bound, maybe one of the right elements is..
|
||||||
|
if (o.right !== null) {
|
||||||
|
o = o.right;
|
||||||
|
} else {
|
||||||
|
// there is no right element. Search for the next bigger element,
|
||||||
|
// this should be within the bounds
|
||||||
|
return o.next();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iterate (from, to, f) {
|
||||||
|
var o = this.findNodeWithLowerBound(from);
|
||||||
|
while ( o !== null && (to === null || o.val.id <= to) ) {
|
||||||
|
f(o.val);
|
||||||
|
o = o.next();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
find (id) {
|
||||||
|
return this.findNode(id).val;
|
||||||
|
}
|
||||||
|
findNode (id) {
|
||||||
|
var o = this.root;
|
||||||
|
if (o === null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
while (true) {
|
||||||
|
if (o === null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (id < o.val.id) {
|
if (id < o.val.id) {
|
||||||
@ -103,25 +159,160 @@ class RBTree { //eslint-disable-line no-unused-vars
|
|||||||
} else if (o.val.id < id) {
|
} else if (o.val.id < id) {
|
||||||
o = o.right;
|
o = o.right;
|
||||||
} else {
|
} else {
|
||||||
return o.val;
|
return o;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
delete (id) {
|
||||||
|
var d = this.findNode(id);
|
||||||
|
if (d.left !== null && d.right !== null) {
|
||||||
|
// switch d with the greates element in the left subtree.
|
||||||
|
// o should have at most one child.
|
||||||
|
var o = d.left;
|
||||||
|
// find
|
||||||
|
while (o.right !== null) {
|
||||||
|
o = o.right;
|
||||||
|
}
|
||||||
|
// switch
|
||||||
|
d.val = o.val;
|
||||||
|
d = o;
|
||||||
|
}
|
||||||
|
// d has at most one child
|
||||||
|
// let n be the node that replaces d
|
||||||
|
var isFakeChild;
|
||||||
|
var child = d.left || d.right;
|
||||||
|
if ( child === null) {
|
||||||
|
isFakeChild = true;
|
||||||
|
child = new N({id: 0});
|
||||||
|
child.blacken();
|
||||||
|
d.right = child;
|
||||||
|
} else {
|
||||||
|
isFakeChild = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d.parent === null) {
|
||||||
|
if (!isFakeChild) {
|
||||||
|
this.root = child;
|
||||||
|
child.blacken();
|
||||||
|
child._parent = null;
|
||||||
|
} else {
|
||||||
|
this.root = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (d.parent.left === d) {
|
||||||
|
d.parent.left = child;
|
||||||
|
} else if (d.parent.right === d) {
|
||||||
|
d.parent.right = child;
|
||||||
|
} else {
|
||||||
|
throw new Error("Impossible!");
|
||||||
|
}
|
||||||
|
if ( d.isBlack() ) {
|
||||||
|
if ( child.isRed() ) {
|
||||||
|
child.blacken();
|
||||||
|
} else {
|
||||||
|
this._fixDelete(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.root.blacken();
|
||||||
|
if (isFakeChild) {
|
||||||
|
if (child.parent.left === child) {
|
||||||
|
child.parent.left = null;
|
||||||
|
} else if (child.parent.right === child) {
|
||||||
|
child.parent.right = null;
|
||||||
|
} else {
|
||||||
|
throw new Error("Impossible #3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_fixDelete (n) {
|
||||||
|
function isBlack (node) {
|
||||||
|
return node !== null ? node.isBlack() : true;
|
||||||
|
}
|
||||||
|
function isRed(node) {
|
||||||
|
return node !== null ? node.isRed() : false;
|
||||||
|
}
|
||||||
|
if (n.parent === null) {
|
||||||
|
// this can only be called after the first iteration of fixDelete.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// d was already replaced by the child
|
||||||
|
// d is not the root
|
||||||
|
// d and child are black
|
||||||
|
var sibling = n.sibling;
|
||||||
|
if (isRed(sibling)) {
|
||||||
|
// make sibling the grandfather
|
||||||
|
n.parent.redden();
|
||||||
|
sibling.blacken();
|
||||||
|
if (n === n.parent.left) {
|
||||||
|
n.parent.rotateLeft(this);
|
||||||
|
} else if (n === n.parent.right) {
|
||||||
|
n.parent.rotateRight(this);
|
||||||
|
} else {
|
||||||
|
throw new Error("Impossible #2");
|
||||||
|
}
|
||||||
|
sibling = n.sibling;
|
||||||
|
}
|
||||||
|
// parent, sibling, and children of n are black
|
||||||
|
if ( n.parent.isBlack() &&
|
||||||
|
sibling.isBlack() &&
|
||||||
|
isBlack(sibling.left) &&
|
||||||
|
isBlack(sibling.right)
|
||||||
|
) {
|
||||||
|
sibling.redden();
|
||||||
|
this._fixDelete(n.parent);
|
||||||
|
} else if ( n.parent.isRed() &&
|
||||||
|
sibling.isBlack() &&
|
||||||
|
isBlack(sibling.left) &&
|
||||||
|
isBlack(sibling.right)
|
||||||
|
) {
|
||||||
|
sibling.redden();
|
||||||
|
n.parent.blacken();
|
||||||
|
} else {
|
||||||
|
if ( n === n.parent.left &&
|
||||||
|
sibling.isBlack() &&
|
||||||
|
isRed(sibling.left) &&
|
||||||
|
isBlack(sibling.right)
|
||||||
|
) {
|
||||||
|
sibling.redden();
|
||||||
|
sibling.left.blacken();
|
||||||
|
sibling.rotateRight(this);
|
||||||
|
sibling = n.sibling;
|
||||||
|
} else if ( n === n.parent.right &&
|
||||||
|
sibling.isBlack() &&
|
||||||
|
isRed(sibling.right) &&
|
||||||
|
isBlack(sibling.left)
|
||||||
|
) {
|
||||||
|
sibling.redden();
|
||||||
|
sibling.right.blacken();
|
||||||
|
sibling.rotateLeft(this);
|
||||||
|
sibling = n.sibling;
|
||||||
|
}
|
||||||
|
sibling.color = n.parent.color;
|
||||||
|
n.parent.blacken();
|
||||||
|
if (n === n.parent.left) {
|
||||||
|
sibling.right.blacken();
|
||||||
|
n.parent.rotateLeft(this);
|
||||||
|
} else {
|
||||||
|
sibling.left.blacken();
|
||||||
|
n.parent.rotateRight(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
add (v) {
|
add (v) {
|
||||||
var node = new N(v);
|
var node = new N(v);
|
||||||
if (this.root != null) {
|
if (this.root !== null) {
|
||||||
var p = this.root; // p abbrev. parent
|
var p = this.root; // p abbrev. parent
|
||||||
while (true) {
|
while (true) {
|
||||||
if (node.val.id < p.val.id) {
|
if (node.val.id < p.val.id) {
|
||||||
if (p.left == null) {
|
if (p.left === null) {
|
||||||
p.left = node;
|
p.left = node;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
p = p.left;
|
p = p.left;
|
||||||
}
|
}
|
||||||
} else if (p.val.id < node.val.id) {
|
} else if (p.val.id < node.val.id) {
|
||||||
if (p.right == null) {
|
if (p.right === null) {
|
||||||
p.right = node;
|
p.right = node;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
@ -131,26 +322,26 @@ class RBTree { //eslint-disable-line no-unused-vars
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.fixInsert(node);
|
this._fixInsert(node);
|
||||||
} else {
|
} else {
|
||||||
this.root = node;
|
this.root = node;
|
||||||
}
|
}
|
||||||
this.root.blacken();
|
this.root.blacken();
|
||||||
}
|
}
|
||||||
fixInsert (n) {
|
_fixInsert (n) {
|
||||||
if (n.parent == null) {
|
if (n.parent === null) {
|
||||||
n.blacken();
|
n.blacken();
|
||||||
return;
|
return;
|
||||||
} else if (n.parent.isBlack()) {
|
} else if (n.parent.isBlack()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var uncle = n.getUncle();
|
var uncle = n.getUncle();
|
||||||
if (uncle != null && uncle.isRed()) {
|
if (uncle !== null && uncle.isRed()) {
|
||||||
// Note: parend: red, uncle: red
|
// Note: parent: red, uncle: red
|
||||||
n.parent.blacken();
|
n.parent.blacken();
|
||||||
uncle.blacken();
|
uncle.blacken();
|
||||||
n.grandparent.redden();
|
n.grandparent.redden();
|
||||||
this.fixInsert(n.grandparent);
|
this._fixInsert(n.grandparent);
|
||||||
} else {
|
} else {
|
||||||
// Note: parent: red, uncle: black or null
|
// Note: parent: red, uncle: black or null
|
||||||
// Now we transform the tree in such a way that
|
// Now we transform the tree in such a way that
|
||||||
|
@ -1,41 +1,9 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
/*eslint-env browser,jasmine */
|
/*eslint-env browser,jasmine,console */
|
||||||
|
|
||||||
var numberOfTests = 100000;
|
var numberOfTests = 10009;
|
||||||
|
|
||||||
describe("RedBlack Tree", function(){
|
function itRedNodesDoNotHaveBlackChildren (tree) {
|
||||||
beforeEach(function(){
|
|
||||||
this.tree = new RBTree();
|
|
||||||
});
|
|
||||||
it("can add&retrieve 5 elements", function(){
|
|
||||||
this.tree.add({val: "four", id: 4});
|
|
||||||
this.tree.add({val: "one", id: 1});
|
|
||||||
this.tree.add({val: "three", id: 3});
|
|
||||||
this.tree.add({val: "two", id: 2});
|
|
||||||
this.tree.add({val: "five", id: 5});
|
|
||||||
expect(this.tree.find(1).val).toEqual("one");
|
|
||||||
expect(this.tree.find(2).val).toEqual("two");
|
|
||||||
expect(this.tree.find(3).val).toEqual("three");
|
|
||||||
expect(this.tree.find(4).val).toEqual("four");
|
|
||||||
expect(this.tree.find(5).val).toEqual("five");
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(`After adding ${numberOfTests} random objects`, function () {
|
|
||||||
var elements = [];
|
|
||||||
var tree = new RBTree();
|
|
||||||
for(var i = 0; i < numberOfTests; i++) {
|
|
||||||
var obj = Math.floor(Math.random() * numberOfTests * 10000);
|
|
||||||
elements.push(obj);
|
|
||||||
tree.add({id: obj});
|
|
||||||
}
|
|
||||||
it("root node is black", function(){
|
|
||||||
expect(tree.root.isBlack()).toBeTruthy();
|
|
||||||
});
|
|
||||||
it("can find every object", function(){
|
|
||||||
for(var id of elements) {
|
|
||||||
expect(tree.find(id).id).toEqual(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it("Red nodes do not have black children", function(){
|
it("Red nodes do not have black children", function(){
|
||||||
function traverse (n) {
|
function traverse (n) {
|
||||||
if (n == null) {
|
if (n == null) {
|
||||||
@ -54,6 +22,9 @@ describe("RedBlack Tree", function(){
|
|||||||
}
|
}
|
||||||
traverse(tree.root);
|
traverse(tree.root);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function itBlackHeightOfSubTreesAreEqual (tree){
|
||||||
it("Black-height of sub-trees are equal", function(){
|
it("Black-height of sub-trees are equal", function(){
|
||||||
function traverse (n) {
|
function traverse (n) {
|
||||||
if (n == null) {
|
if (n == null) {
|
||||||
@ -70,5 +41,169 @@ describe("RedBlack Tree", function(){
|
|||||||
}
|
}
|
||||||
traverse(tree.root);
|
traverse(tree.root);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function itRootNodeIsBlack(tree) {
|
||||||
|
it("root node is black", function(){
|
||||||
|
expect(tree.root == null || tree.root.isBlack()).toBeTruthy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("RedBlack Tree", function(){
|
||||||
|
beforeEach(function(){
|
||||||
|
this.tree = new RBTree();
|
||||||
|
});
|
||||||
|
it("can add&retrieve 5 elements", function(){
|
||||||
|
this.tree.add({val: "four", id: 4});
|
||||||
|
this.tree.add({val: "one", id: 1});
|
||||||
|
this.tree.add({val: "three", id: 3});
|
||||||
|
this.tree.add({val: "two", id: 2});
|
||||||
|
this.tree.add({val: "five", id: 5});
|
||||||
|
expect(this.tree.find(1).val).toEqual("one");
|
||||||
|
expect(this.tree.find(2).val).toEqual("two");
|
||||||
|
expect(this.tree.find(3).val).toEqual("three");
|
||||||
|
expect(this.tree.find(4).val).toEqual("four");
|
||||||
|
expect(this.tree.find(5).val).toEqual("five");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("5 elements do not exist anymore after deleting them", function(){
|
||||||
|
this.tree.add({val: "four", id: 4});
|
||||||
|
this.tree.add({val: "one", id: 1});
|
||||||
|
this.tree.add({val: "three", id: 3});
|
||||||
|
this.tree.add({val: "two", id: 2});
|
||||||
|
this.tree.add({val: "five", id: 5});
|
||||||
|
this.tree.delete(4);
|
||||||
|
expect(this.tree.find(4)).not.toBeTruthy();
|
||||||
|
this.tree.delete(3);
|
||||||
|
expect(this.tree.find(3)).not.toBeTruthy();
|
||||||
|
this.tree.delete(2);
|
||||||
|
expect(this.tree.find(2)).not.toBeTruthy();
|
||||||
|
this.tree.delete(1);
|
||||||
|
expect(this.tree.find(1)).not.toBeTruthy();
|
||||||
|
this.tree.delete(5);
|
||||||
|
expect(this.tree.find(5)).not.toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("debug #1", function(){
|
||||||
|
this.tree.add({id: 2});
|
||||||
|
this.tree.add({id: 0});
|
||||||
|
this.tree.delete(2);
|
||||||
|
this.tree.add({id: 1});
|
||||||
|
expect(this.tree.find(0)).not.toBeUndefined();
|
||||||
|
expect(this.tree.find(1)).not.toBeUndefined();
|
||||||
|
expect(this.tree.find(2)).toBeUndefined();
|
||||||
|
});
|
||||||
|
describe("debug #2", function(){
|
||||||
|
var tree = new RBTree();
|
||||||
|
tree.add({id: 8433});
|
||||||
|
tree.add({id: 12844});
|
||||||
|
tree.add({id: 1795});
|
||||||
|
tree.add({id: 30302});
|
||||||
|
tree.add({id: 64287});
|
||||||
|
tree.delete(8433);
|
||||||
|
tree.add({id: 28996});
|
||||||
|
tree.delete(64287);
|
||||||
|
tree.add({id: 22721});
|
||||||
|
|
||||||
|
itRootNodeIsBlack(tree, []);
|
||||||
|
itBlackHeightOfSubTreesAreEqual(tree, []);
|
||||||
|
itRedNodesDoNotHaveBlackChildren(tree, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(`After adding&deleting (0.8/0.2) ${numberOfTests} times`, function () {
|
||||||
|
var elements = [];
|
||||||
|
var tree = new RBTree();
|
||||||
|
for(var i = 0; i < numberOfTests; i++) {
|
||||||
|
var r = Math.random();
|
||||||
|
if (r < 0.8) {
|
||||||
|
var obj = Math.floor(Math.random() * numberOfTests * 10000);
|
||||||
|
elements.push(obj);
|
||||||
|
tree.add({id: obj});
|
||||||
|
} else if (elements.length > 0) {
|
||||||
|
var elemid = Math.floor(Math.random() * elements.length);
|
||||||
|
var elem = elements[elemid];
|
||||||
|
elements = elements.filter(function(e){return e != elem; }); //eslint-disable-line
|
||||||
|
tree.delete(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itRootNodeIsBlack(tree);
|
||||||
|
|
||||||
|
it("can find every object", function(){
|
||||||
|
for(var id of elements) {
|
||||||
|
expect(tree.find(id).id).toEqual(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can find every object with lower bound search", function(){
|
||||||
|
for(var id of elements) {
|
||||||
|
expect(tree.findNodeWithLowerBound(id).val.id).toEqual(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
itRedNodesDoNotHaveBlackChildren(tree);
|
||||||
|
|
||||||
|
itBlackHeightOfSubTreesAreEqual(tree);
|
||||||
|
|
||||||
|
it("iterating over a tree with lower bound yields the right amount of results", function(){
|
||||||
|
var lowerBound = elements[Math.floor(Math.random() * elements.length)];
|
||||||
|
var expectedResults = elements.filter(function(e, pos){
|
||||||
|
return e >= lowerBound && elements.indexOf(e) === pos;
|
||||||
|
}).length;
|
||||||
|
|
||||||
|
var actualResults = 0;
|
||||||
|
tree.iterate(lowerBound, null, function(val){
|
||||||
|
expect(val).not.toBeUndefined();
|
||||||
|
actualResults++;
|
||||||
|
});
|
||||||
|
expect(expectedResults).toEqual(actualResults);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("iterating over a tree without bounds yield the right amount of results", function(){
|
||||||
|
var lowerBound = null;
|
||||||
|
var expectedResults = elements.filter(function(e, pos){
|
||||||
|
return elements.indexOf(e) === pos;
|
||||||
|
}).length;
|
||||||
|
var actualResults = 0;
|
||||||
|
tree.iterate(lowerBound, null, function(val){
|
||||||
|
expect(val).not.toBeUndefined();
|
||||||
|
actualResults++;
|
||||||
|
});
|
||||||
|
expect(expectedResults).toEqual(actualResults);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("iterating over a tree with upper bound yields the right amount of results", function(){
|
||||||
|
var upperBound = elements[Math.floor(Math.random() * elements.length)];
|
||||||
|
var expectedResults = elements.filter(function(e, pos){
|
||||||
|
return e <= upperBound && elements.indexOf(e) === pos;
|
||||||
|
}).length;
|
||||||
|
|
||||||
|
var actualResults = 0;
|
||||||
|
tree.iterate(null, upperBound, function(val){
|
||||||
|
expect(val).not.toBeUndefined();
|
||||||
|
actualResults++;
|
||||||
|
});
|
||||||
|
expect(expectedResults).toEqual(actualResults);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("iterating over a tree with upper and lower bounds yield the right amount of results", function(){
|
||||||
|
var b1 = elements[Math.floor(Math.random() * elements.length)];
|
||||||
|
var b2 = elements[Math.floor(Math.random() * elements.length)];
|
||||||
|
var upperBound, lowerBound;
|
||||||
|
if (b1 < b2) {
|
||||||
|
lowerBound = b1;
|
||||||
|
upperBound = b2;
|
||||||
|
} else {
|
||||||
|
lowerBound = b2;
|
||||||
|
upperBound = b1;
|
||||||
|
}
|
||||||
|
var expectedResults = elements.filter(function(e, pos){
|
||||||
|
return e >= lowerBound && e <= upperBound && elements.indexOf(e) === pos;
|
||||||
|
}).length;
|
||||||
|
var actualResults = 0;
|
||||||
|
tree.iterate(lowerBound, upperBound, function(val){
|
||||||
|
expect(val).not.toBeUndefined();
|
||||||
|
actualResults++;
|
||||||
|
});
|
||||||
|
expect(expectedResults).toEqual(actualResults);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user