-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
312 additions
and
2 deletions.
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
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,144 @@ | ||
describe("Tree", function() { | ||
var tree = null; | ||
|
||
beforeEach(function() { | ||
tree = new Tree(1); | ||
tree._root.children.push(new Node(2)); | ||
tree._root.children[0].parent = tree; | ||
tree._root.children.push(new Node(3)); | ||
tree._root.children[1].parent = tree; | ||
tree._root.children.push(new Node(4)); | ||
tree._root.children[2].parent = tree; | ||
|
||
tree._root.children[0].children.push(new Node(5)); | ||
tree._root.children[0].children[0].parent = tree._root.children[0]; | ||
|
||
tree._root.children[0].children.push(new Node(6)); | ||
tree._root.children[0].children[1].parent = tree._root.children[0]; | ||
|
||
tree._root.children[2].children.push(new Node(7)); | ||
tree._root.children[2].children[0].parent = tree._root.children[2]; | ||
|
||
// 1 | ||
// / | \ | ||
// 2 3 4 | ||
// / \ | | ||
// 5 6 7 | ||
}); | ||
|
||
it("should have 1 as root's data", function() { | ||
expect(tree._root.data).toEqual(1); | ||
}); | ||
|
||
it("should have null as root's parent", function() { | ||
expect(tree._root.parent).toEqual(null); | ||
}); | ||
|
||
it("should have [] as root's children", function() { | ||
expect(tree._root.children).toEqual(jasmine.any(Array)); | ||
}); | ||
|
||
describe("#traverseDF(callback)", function() { | ||
var sequence = ''; | ||
|
||
beforeEach(function() { | ||
tree.traverseDF(function(node) { | ||
sequence += node.data; | ||
}); | ||
}); | ||
|
||
it("should have the correct sequence", function() { | ||
expect(sequence).toEqual("5623741"); | ||
}); | ||
}); | ||
|
||
describe("#traverseBF(callback)", function() { | ||
var sequence = ''; | ||
|
||
beforeEach(function() { | ||
tree.traverseBF(function(node) { | ||
sequence += node.data; | ||
}); | ||
}); | ||
|
||
it("should have the correct sequence", function() { | ||
expect(sequence).toEqual("1234567"); | ||
}); | ||
}); | ||
|
||
describe("#contains(callback, traversal)", function() { | ||
it("should return even numbers with DFS", function() { | ||
var sequence = ''; | ||
|
||
tree.contains(function(node) { | ||
if (!(node.data % 2)) { | ||
sequence += node.data; | ||
} | ||
}, tree.traverseDF); | ||
|
||
expect(sequence).toEqual("624"); | ||
}); | ||
|
||
it("should return even numbers with BFS", function() { | ||
var sequence = ''; | ||
|
||
tree.contains(function(node) { | ||
if (!(node.data % 2)) { | ||
sequence += node.data; | ||
} | ||
}, tree.traverseBF); | ||
|
||
expect(sequence).toEqual("246"); | ||
}); | ||
}); | ||
|
||
describe("#add(data, toData, traverse)", function() { | ||
var sequence = ''; | ||
|
||
it("should add node with a valid data of 8", function() { | ||
tree.add(8, 4, tree.traverseBF); | ||
tree.traverseBF(function(node) { | ||
sequence += node.data; | ||
}); | ||
|
||
expect(sequence).toEqual("12345678"); | ||
}); | ||
|
||
it("should throw an error with an invalid parent", function() { | ||
expect(function() { | ||
tree.add(9, 400, tree.traverseBF); | ||
}).toThrowError("Cannot add node to a non-existent parent."); | ||
}); | ||
}); | ||
|
||
describe("#remove(data, toData, traverse)", function() { | ||
var sequence = ''; | ||
|
||
beforeEach(function() { | ||
tree.add(8, 4, tree.traverseBF); | ||
}); | ||
|
||
it("should remove node with a valid data of 8", function() { | ||
tree.remove(8, 4, tree.traverseBF); | ||
tree.traverseBF(function(node) { | ||
sequence += node.data; | ||
}); | ||
|
||
expect(sequence).toEqual("1234567"); | ||
}); | ||
|
||
it("should throw an error with an invalid parent", function() { | ||
expect(function() { | ||
tree.remove(8, 400, tree.traverseBF); | ||
}).toThrowError("Parent does not exist."); | ||
}); | ||
|
||
it("should throw an error with an invalid node", function() { | ||
expect(function() { | ||
tree.remove(80, 4, tree.traverseBF); | ||
}).toThrowError("Node to remove does not exist."); | ||
}); | ||
}); | ||
}); | ||
|
||
|
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,20 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>Jasmine Spec Runner v2.2.0</title> | ||
|
||
<link rel="shortcut icon" type="image/png" href="../lib/jasmine-2.2.0/jasmine_favicon.png"> | ||
<link rel="stylesheet" href="../lib/jasmine-2.2.0/jasmine.css"> | ||
|
||
<script src="../lib/jasmine-2.2.0/jasmine.js"></script> | ||
<script src="../lib/jasmine-2.2.0/jasmine-html.js"></script> | ||
<script src="../lib/jasmine-2.2.0/boot.js"></script> | ||
|
||
<script src="../src/tree.js"></script> | ||
<script src="../spec/tree_spec.js"></script> | ||
</head> | ||
|
||
<body> | ||
</body> | ||
</html> |
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,145 @@ | ||
function Node(data) { | ||
this.data = data; | ||
this.parent = null; | ||
this.children = []; | ||
} | ||
|
||
function Tree(data) { | ||
var node = new Node(data); | ||
this._root = node; | ||
} | ||
|
||
Tree.prototype.traverseDF = function(callback) { | ||
|
||
// this is a recursive and immediately-invoking function | ||
(function recurse(currentNode) { | ||
|
||
// step 2 | ||
for (var i = 0, length = currentNode.children.length; i < length; i++) { | ||
|
||
// step 3 | ||
recurse(currentNode.children[i]); | ||
} | ||
|
||
// step 4 | ||
callback(currentNode); | ||
|
||
// step 1 | ||
})(this._root); | ||
|
||
}; | ||
|
||
Tree.prototype.traverseBF = function(callback) { | ||
var queue = new Queue(); | ||
queue.enqueue(this._root); | ||
|
||
currentTree = queue.dequeue(); | ||
|
||
while(currentTree){ | ||
for (var i = 0, length = currentTree.children.length; i < length; i++) { | ||
queue.enqueue(currentTree.children[i]); | ||
} | ||
|
||
callback(currentTree); | ||
currentTree = queue.dequeue(); | ||
} | ||
}; | ||
|
||
Tree.prototype.contains = function(callback, traversal) { | ||
traversal.call(this, callback); | ||
}; | ||
|
||
Tree.prototype.add = function(data, toData, traversal) { | ||
var child = new Node(data), | ||
parent = null, | ||
callback = function(node) { | ||
if (node.data === toData) { | ||
parent = node; | ||
} | ||
}; | ||
|
||
this.contains(callback, traversal); | ||
|
||
if (!parent) { | ||
throw new Error("Cannot add node to a non-existent parent."); | ||
} else { | ||
parent.children.push(child); | ||
child.parent = parent; | ||
} | ||
}; | ||
|
||
Tree.prototype.remove = function(data, fromData, traversal) { | ||
var tree = this, | ||
parent = null, | ||
childToRemove = null, | ||
index; | ||
|
||
var callback = function(node) { | ||
if (node.data === fromData) { | ||
parent = node; | ||
} | ||
}; | ||
|
||
this.contains(callback, traversal); | ||
|
||
if (!parent) { | ||
throw new Error("Parent does not exist."); | ||
|
||
} else { | ||
index = findIndex(parent.children, data); | ||
|
||
if (index === undefined) { | ||
throw new Error("Node to remove does not exist."); | ||
} else { | ||
childToRemove = parent.children.splice(index, 1); | ||
} | ||
|
||
} | ||
|
||
return childToRemove; | ||
}; | ||
|
||
// Helper Method of Tree | ||
function findIndex(arr, data) { | ||
var index; | ||
|
||
for (var i = 0; i < arr.length; i++) { | ||
if (arr[i].data === data) { | ||
index = i; | ||
} | ||
} | ||
|
||
return index; | ||
} | ||
|
||
// Queue Constructor | ||
function Queue() { | ||
this._oldestIndex = 1; | ||
this._newestIndex = 1; | ||
this._storage = {}; | ||
} | ||
|
||
Queue.prototype.size = function() { | ||
return this._newestIndex - this._oldestIndex; | ||
}; | ||
|
||
Queue.prototype.enqueue = function(data) { | ||
this._storage[this._newestIndex] = data; | ||
this._newestIndex++; | ||
}; | ||
|
||
Queue.prototype.dequeue = function() { | ||
var oldestIndex = this._oldestIndex, | ||
newestIndex = this._newestIndex, | ||
deletedData; | ||
|
||
if (oldestIndex === newestIndex) { | ||
return; | ||
} else { | ||
deletedData = this._storage[oldestIndex]; | ||
delete this._storage[oldestIndex]; | ||
this._oldestIndex++; | ||
|
||
return deletedData; | ||
} | ||
}; |