This repository has been archived by the owner on Feb 19, 2023. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- BTree has get and insert - Remove not yet implemented
- Loading branch information
1 parent
3dae37f
commit 0b8022d
Showing
3 changed files
with
350 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
|
||
|
||
function Leaf(key, data) { | ||
this.key = key; | ||
this.data = data; | ||
} | ||
|
||
|
||
function Node(parent, size) { | ||
this.leafs = []; | ||
this.nodes = []; | ||
this.parent = parent; | ||
this.size = size; | ||
} | ||
|
||
Node.prototype.getLeaf = function(key) { | ||
|
||
var ctLeaf, ltNode, rtNode, result; | ||
for(var i = 0; i < this.size; i += 1) { | ||
|
||
ctLeaf = this.leafs[i]; | ||
ltNode = this.nodes[i]; | ||
rtNode = this.nodes[i + 1]; | ||
|
||
// if a leaf exists in the current slot | ||
if(ctLeaf) { | ||
|
||
// if a direct key match return the | ||
// leaf | ||
if(ctLeaf.key == key) { | ||
return ctLeaf; | ||
} | ||
|
||
// if the key is lesser and a left | ||
// sub node exists | ||
else if(ctLeaf.key > key && ltNode) { | ||
result = ltNode.getLeaf(key); | ||
if(result) { return result; } | ||
} | ||
|
||
// if the key is greater and a right | ||
// sub node exists | ||
else if(ctLeaf.key < key && rtNode) { | ||
result = rtNode.getLeaf(key); | ||
if(result) { return result; } | ||
} | ||
} | ||
|
||
// return an empty result | ||
return; | ||
} | ||
} | ||
|
||
Node.prototype.insertLeaf = function(leaf, upTree) { | ||
|
||
// loop through all slots within the node | ||
var ctLeaf, ntLeaf, ltNode, rtNode; | ||
for(var i = 0; i < this.size + 1; i += 1) { | ||
|
||
ctLeaf = this.leafs[i]; | ||
ntLeaf = this.leafs[i + 1]; | ||
ltNode = this.nodes[i]; | ||
rtNode = this.nodes[i + 1]; | ||
|
||
// if there is a key | ||
if(ctLeaf) { | ||
|
||
// if the keys match | ||
if(ctLeaf.key == leaf.key) { | ||
// replace the data | ||
ctLeaf.data = leaf.data; | ||
break; | ||
} | ||
|
||
// if the key is greater and a node | ||
// exists to the right but there | ||
// is no leaf to following the current | ||
else if(ctLeaf.key < leaf.key && !ntLeaf && rtNode && !upTree) { | ||
// insert into the right node | ||
rtNode.insertLeaf(leaf); | ||
break; | ||
} | ||
|
||
// if the key is lesser | ||
else if(ctLeaf.key > leaf.key) { | ||
|
||
// if a left node exists to the | ||
// right | ||
if(ltNode && !upTree) { | ||
// insert into the left node | ||
ltNode.insertLeaf(leaf); | ||
break; | ||
} | ||
|
||
// if there isn't a left node | ||
else { | ||
// insert before the current | ||
// leaf | ||
this.leafs.splice(i, 0, leaf); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
// if the slot is empty | ||
else { | ||
|
||
// insert the leaf | ||
this.leafs[i] = leaf; | ||
break; | ||
} | ||
} | ||
|
||
// if the leaf overflows | ||
if(this.leafs.length > this.size) { | ||
this._split(); | ||
} | ||
|
||
}; | ||
|
||
Node.prototype.removeLeaf = function(key) { | ||
|
||
}; | ||
|
||
Node.prototype._split = function() { | ||
|
||
// seperate the middle and right leafs | ||
var groupSize = Math.floor(this.size / 2); | ||
var middleLeaf = this.leafs.splice(groupSize, 1)[0]; | ||
var rightLeafs = this.leafs.splice(groupSize); | ||
|
||
// collect the right nodes | ||
var rightNodes = this.nodes.splice(groupSize + 1); | ||
|
||
// if this is the root node | ||
var qTree; | ||
if(this.parent.root) { | ||
qTree = this.parent; | ||
this.parent = new Node(qTree, this.size); | ||
this.parent.nodes.push(this); | ||
qTree.root = this.parent; | ||
} | ||
|
||
// insert the middle leaf into the parent node | ||
this.parent.insertLeaf(middleLeaf, true); | ||
|
||
|
||
// create the right node | ||
var rightNode = new Node(this.parent, this.size); | ||
this.parent.nodes.push(rightNode); | ||
while(rightLeafs[0]) { rightNode.insertLeaf(rightLeafs.shift(), true); } | ||
var subNode; | ||
while(rightNodes[0]) { | ||
var subNode = rightNodes.shift(); | ||
subNode.parent = rightNode; | ||
rightNode.nodes.push(subNode); | ||
} | ||
}; | ||
|
||
|
||
function BTree(nodeSize) { | ||
|
||
nodeSize = nodeSize || 2; | ||
|
||
if(typeof nodeSize != 'number' || nodeSize < 1) { throw new Error('nodeSize must be a number greater than zero'); } | ||
if(typeof maxDepth != 'number' || maxDepth < 1) { throw new Error('maxDepth must be greater than zero'); } | ||
|
||
this.root = new Node(this, size); | ||
} | ||
|
||
BTree.Node = Node; | ||
BTree.Leaf = Leaf; | ||
|
||
BTree.prototype.insert = function(key, data) { | ||
var leaf = new Leaf(key, data); | ||
this.root.insertLeaf(leaf); | ||
}; | ||
|
||
BTree.prototype.get = function(key) { | ||
var leaf = this.root.getLeaf(key); | ||
return leaf.data; | ||
}; | ||
|
||
BTree.prototype.remove = function(key) { | ||
var leaf = this.root.removeLeaf(key); | ||
return leaf; | ||
}; | ||
|
||
BTree.prototype.truncate = function() { | ||
|
||
// replace the entire root node; deleting all | ||
// data within the previous root node and its | ||
// tree or sub nodes. | ||
this.root = new Node(this, this.root.size); | ||
|
||
}; | ||
|
||
module.exports = BTree; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
|
||
// as trees are added to the library they should | ||
// be requred and exported below | ||
exports.Rect = require('./lib/rect'); | ||
exports.BTree = require('./lib/b-tree'); | ||
exports.QuadTree = require('./lib/quad-tree'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
var BTree = require('../').BTree; | ||
var should = require('should'); | ||
|
||
|
||
describe('Leaf', function() { | ||
|
||
var leaf; | ||
beforeEach(function() { | ||
leaf = new BTree.Leaf('key', 'leaf'); | ||
}); | ||
|
||
describe('key', function() { | ||
it('should be equal to the key given to the leaf constructor', function() { | ||
leaf.key.should.be.equal('key'); | ||
}); | ||
}); | ||
|
||
describe('data', function() { | ||
it('should be equal to the data given to the leaf constructor', function() { | ||
leaf.data.should.be.equal('leaf'); | ||
}); | ||
}); | ||
}); | ||
|
||
|
||
describe('Node', function() { | ||
|
||
var node; | ||
beforeEach(function() { | ||
var fakeBTree = {}; | ||
node = new BTree.Node(fakeBTree, 2); | ||
fakeBTree.root = node; | ||
}); | ||
|
||
describe('getLeaf', function() { | ||
|
||
it('should return a leaf with a matching key', function() { | ||
node.insertLeaf(new BTree.Leaf(3, 'three')); | ||
node.insertLeaf(new BTree.Leaf(1, 'one')); | ||
node.insertLeaf(new BTree.Leaf(2, 'two')); | ||
node = node.parent; | ||
|
||
var leaf = node.getLeaf(3); | ||
leaf.key.should.equal(3); | ||
leaf.data.should.equal('three'); | ||
|
||
leaf = node.getLeaf(2); | ||
leaf.key.should.equal(2); | ||
leaf.data.should.equal('two'); | ||
|
||
leaf = node.getLeaf(1); | ||
leaf.key.should.equal(1); | ||
leaf.data.should.equal('one'); | ||
}); | ||
|
||
it('should return undefined if there is no leaf with the given key', function() { | ||
node.insertLeaf(new BTree.Leaf(3, 'three')); | ||
node.insertLeaf(new BTree.Leaf(1, 'one')); | ||
node.insertLeaf(new BTree.Leaf(2, 'two')); | ||
node = node.parent; | ||
|
||
var leaf = node.getLeaf(5); | ||
should.not.exist(leaf); | ||
}); | ||
|
||
}); | ||
|
||
describe('insertLeaf', function() { | ||
|
||
it('should accept inserted data', function() { | ||
node.insertLeaf(new BTree.Leaf(1, 'one')); | ||
node.leafs[0].key.should.equal(1); | ||
node.leafs[0].data.should.equal('one'); | ||
}); | ||
|
||
it('should split after the maximum leaf count is reached', function() { | ||
node.insertLeaf(new BTree.Leaf(3, 'three')); | ||
node.insertLeaf(new BTree.Leaf(1, 'one')); | ||
node.insertLeaf(new BTree.Leaf(2, 'two')); | ||
node = node.parent; | ||
|
||
node.leafs[0].key.should.equal(2); | ||
node.leafs[0].data.should.equal('two'); | ||
|
||
node.nodes[0].leafs[0].key.should.equal(1); | ||
node.nodes[0].leafs[0].data.should.equal('one'); | ||
|
||
node.nodes[1].leafs[0].key.should.equal(3); | ||
node.nodes[1].leafs[0].data.should.equal('three'); | ||
|
||
}); | ||
|
||
it('should insert into sub nodes when possible', function() { | ||
node.insertLeaf(new BTree.Leaf(1, 'one')); | ||
node.insertLeaf(new BTree.Leaf(6, 'six')); | ||
node.insertLeaf(new BTree.Leaf(3, 'three')); | ||
node = node.parent; | ||
node.insertLeaf(new BTree.Leaf(4, 'four')); | ||
node.insertLeaf(new BTree.Leaf(8, 'eight')); | ||
node.insertLeaf(new BTree.Leaf(5, 'five')); | ||
node.insertLeaf(new BTree.Leaf(7, 'seven')); | ||
node.insertLeaf(new BTree.Leaf(9, 'nine')); | ||
node = node.parent; | ||
node.insertLeaf(new BTree.Leaf(2, 'two')); | ||
|
||
// console.log(require('util').inspect(node.parent.root, { depth: null })); | ||
|
||
node.nodes[0].nodes[0].leafs[0].key.should.equal(1); | ||
node.nodes[0].nodes[0].leafs[0].data.should.equal('one'); | ||
|
||
node.nodes[0].nodes[0].leafs[1].key.should.equal(2); | ||
node.nodes[0].nodes[0].leafs[1].data.should.equal('two'); | ||
|
||
node.nodes[0].leafs[0].key.should.equal(3); | ||
node.nodes[0].leafs[0].data.should.equal('three'); | ||
|
||
node.nodes[0].nodes[1].leafs[0].key.should.equal(4); | ||
node.nodes[0].nodes[1].leafs[0].data.should.equal('four'); | ||
|
||
node.nodes[0].nodes[1].leafs[1].key.should.equal(5); | ||
node.nodes[0].nodes[1].leafs[1].data.should.equal('five'); | ||
|
||
node.leafs[0].key.should.equal(6); | ||
node.leafs[0].data.should.equal('six'); | ||
|
||
node.nodes[1].nodes[0].leafs[0].key.should.equal(7); | ||
node.nodes[1].nodes[0].leafs[0].data.should.equal('seven'); | ||
|
||
node.nodes[1].leafs[0].key.should.equal(8); | ||
node.nodes[1].leafs[0].data.should.equal('eight'); | ||
|
||
node.nodes[1].nodes[1].leafs[0].key.should.equal(9); | ||
node.nodes[1].nodes[1].leafs[0].data.should.equal('nine'); | ||
}); | ||
|
||
it('should allow overwriting existing data', function() { | ||
node.insertLeaf(new BTree.Leaf(1, 'one')); | ||
node.insertLeaf(new BTree.Leaf(2, 'two')); | ||
node.insertLeaf(new BTree.Leaf(3, 'three')); | ||
node = node.parent; | ||
node.insertLeaf(new BTree.Leaf(2, '_two')); | ||
|
||
node.leafs[0].key.should.equal(2); | ||
node.leafs[0].data.should.equal('_two'); | ||
}); | ||
|
||
}); | ||
}); | ||
|
||
describe('BTree', function() { | ||
}); |