Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"description": "LambdaSchool's Data Structures II",
"main": "index.js",
"scripts": {
"test:nolint": "jest --verbose",
"mytest": "npm run test:nolint -- --watch",
"test": "eslint tests/*.js && eslint src/*.js && jest --verbose",
"lint": "eslint",
"test:watch": "npm test -- --watch"
Expand Down
56 changes: 51 additions & 5 deletions src/binary-search-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
/* eslint-disable global-require */
/* eslint-disable no-unused-vars */
/* eslint-disable no-trailing-spaces */
const Queue = require('./queue-helper');

class BinarySearchTree {
constructor(value) {
this.value = value;
Expand All @@ -12,26 +14,70 @@ class BinarySearchTree {
// assigns it to either the left or right subtree,
// depending on its value
insert(value) {

if (this.value === null) {
this.value = new BinarySearchTree(value);
return;
}
if (value > this.value) {
if (!this.right) {
this.right = new BinarySearchTree(value);
return;
}
return this.right.insert(value);
}
if (value <= this.value) {
if (!this.left) {
this.left = new BinarySearchTree(value);
return;
}
return this.left.insert(value);
}
}

// Checks the binary search tree for the input target
// Can be written recursively or iteratively
contains(target) {

if (this.value === target) return true;
if (target > this.value && this.right !== null) {
return this.right.contains(target);
}
if (target <= this.value && this.left !== null) {
return this.left.contains(target);
}
return false;
}
// Traverses the tree in a depth-first manner, i.e. from top to bottom
// Applies the given callback to each tree node in the process
depthFirstForEach(cb) {

cb(this.value);
if (this.left) {
this.left.depthFirstForEach(cb);
}
if (this.right) {
this.right.depthFirstForEach(cb);
}
}
// Traverses the tree in a breadth-first manner, i.e. in layers, starting
// Traverses the tree in a breadth-first manner, i.e. in layers, starting
// at the root node, going down to the root node's children, and iterating
// through all those nodes first before moving on to the next layer of nodes
// Applies the given callback to each tree node in the process
// You'll need the queue-helper file for this. Or could you roll your own queue
// again. Whatever floats your boat.
breadthFirstForEach(cb) {

const q = new Queue();
if (this.value === null) { return; }
q.enqueue(this);
let currentNode = this;
while (!q.isEmpty()) {
currentNode = q.dequeue();
if (currentNode.left) {
q.enqueue(currentNode.left);
}
if (currentNode.right) {
q.enqueue(currentNode.right);
}
cb(currentNode.value);
}
}
}

Expand Down
81 changes: 70 additions & 11 deletions src/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,45 +35,104 @@ class Graph {
this.vertices = [];
}
// Wraps the input value in a new GraphNode and adds it to the array of vertices
// If there are only two nodes in the graph, they need to be automatically
// If there are only two nodes in the graph, they need to be automatically
// connected via an edge
// Optionally accepts an array of other GraphNodes for the new vertex to be connected to
// Returns the newly-added vertex
addVertex(value, edges = []) {

const ngn = new GraphNode({ value, edges });
for (let i = 0; i < edges.length; i++) {
const edgeIndex = this.vertices.indexOf(edges[i]);
this.vertices[edgeIndex].pushToEdges(ngn);
}
this.vertices.push(ngn);
if (this.vertices.length === 2) {
this.vertices[0].pushToEdges(ngn);
this.vertices[1].pushToEdges(this.vertices[0]);
}
return ngn;
}

// Checks all the vertices of the graph for the target value
// Returns true or false
contains(value) {

if (this.vertices.length === 0) return false;
for (let i = 0; i < this.vertices.length; i++) {
if (this.vertices[i].value === value) {
return true;
}
return false;
}
}
// Checks the graph to see if a GraphNode with the specified value exists in the graph
// Checks the graph to see if a GraphNode with the specified value exists in the graph
// and removes the vertex if it is found
// This function should also handle the removing of all edge references for the removed vertex
removeVertex(value) {

// CRC: removeVertex with reduce.
// this.vertices = this.vertices.reduce( (acc, vertex) ) => {
// if (vertex.value === value) {
// vertex.edges.forEach( (edge) => {
// this.removeEdge(item, edge);
// })
// return acc;
// }
// acc.push(vertex);
// return acc;
// }
removeVertex(value) {
let removed;
if (!this.contains(value)) return;
if (this.contains(value)) {
for (let i = 0; i < this.vertices.length; i++) {
if (this.vertices[i].value === value) {
removed = this.vertices[i];
const newVertices = this.vertices.filter(vert => vert.value !== value);
this.vertices = newVertices;
}
}
if (removed.edges.length > 0) {
removed.edges.forEach((edge) => {
this.removeEdge(removed, edge);
});
}
}
}

// Checks the two input vertices to see if each one references the other in their respective edges array
// Both vertices must reference each other for the edge to be considered valid
// If only one vertex references the other but not vice versa, should not return true
// Note: You'll need to store references to each vertex's array of edges so that you can use
// Note: You'll need to store references to each vertex's array of edges so that you can use
// array methods on said arrays. There is no method to traverse the edge arrays built into the GraphNode class
// CRC: Can also use includes method on array
checkIfEdgeExists(fromVertex, toVertex) {

this.contains(fromVertex); //
if (fromVertex.edges.indexOf(toVertex) === -1 || toVertex.edges.indexOf(fromVertex) === -1) {
return false;
}
return true;
}
// Adds an edge between the two given vertices if no edge already exists between them
// Again, an edge means both vertices reference the other
// Again, an edge means both vertices reference the other
addEdge(fromVertex, toVertex) {

if (this.checkIfEdgeExists(fromVertex, toVertex)) return;
fromVertex.pushToEdges(toVertex);
toVertex.pushToEdges(fromVertex);
}
// Removes the edge between the two given vertices if an edge already exists between them
// After removing the edge, neither vertex should be referencing the other
// If a vertex would be left without any edges as a result of calling this function, those
// vertices should be removed as well
// CRC: Solution for getting rid of edge-less vertices using reduce
// this.vertices = this.vertices.reduce( (acc, vertex) => {
// if (vertex.edges.length !== 0) acc.push(vertex);
// return acc;
// }, [])
removeEdge(fromVertex, toVertex) {

fromVertex.edges = fromVertex.edges.filter(edge => edge.value !== toVertex.value);
toVertex.edges = toVertex.edges.filter(edge => edge.value !== fromVertex.value);
if (fromVertex.numberOfEdges === 0) this.removeVertex(fromVertex.value);
if (toVertex.numberOfEdges === 0) this.removeVertex(toVertex.value);
}
}

module.exports = Graph;

49 changes: 43 additions & 6 deletions src/heap.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,75 @@ class Heap {
// Inserts the given value in the heap
// Calls bubbleUp in order to put the newly-inserted element in the right place in the heap
insert(val) {

this.storage.push(val);
this.size++;
let index = this.storage.length - 1;
this.bubbleUp(index);
}
// Deletes the element located at the front of the heap (the max if a max heap, or a min if a min heap)
// Calls siftDown in order to reorganize the heap with a new max/min
// In some specifications, this method is also called `poll`
delete() {

const deleted = this.getMax();
this.storage = [null].concat(this.storage.slice(2));
// this.storage = this.storage.splice(1,1); Why doesn't this work!?
this.size--;
let index = 1;
while (index <= this.size) {
this.siftDown(index);
index++;
}
return deleted;
}
// Returns the maximum value in the heap in constant time
getMax() {
return this.storage[1];

}
// Returns the size of the heap
getSize() {

return this.size;
}
// Returns the storage array
getStorage() {

return this.storage;
}
// Moves the element at the specified index "up" by swapping it with its parent
// if its parent value is less than the value located at the input index
// This method is only used by the heap itself in order to maintain the heap property
bubbleUp(index) {

while (this.storage[index] > this.storage[Math.ceil(index/2)]) {
if (index > 1) {
[this.storage[Math.ceil(index/2)], this.storage[index]] = [this.storage[index], this.storage[Math.ceil(index/2)]];
if (Math.ceil(index/2) > 1) {
index = Math.ceil(index/2)
} else { break; }
}
}
}
// First grabs the indices of this element's children and determines which of the children are larger
// If the larger of the child elements is larger than the parent, the child element is swapped with the parent
// This method is only used by the heap itself in order to maintain the heap property
siftDown(index) {

let child1 = this.storage[Math.ceil(index*2)];
let c1index = Math.ceil(index*2);
let child2 = this.storage[Math.ceil(index*2 + 1)];
let c2index = Math.ceil(index*2 + 1);
let greaterChild;
let gcIndex;
if (child1 >= child2 || child2 === undefined) {
greaterChild = child1;
gcIndex = c1index;
} else {
greaterChild = child2;
gcIndex = c2index; // not needed to pass test, but I assume we need?
}
if (greaterChild > this.storage[index]) {
[this.storage[gcIndex], this.storage[index]] = [this.storage[index], this.storage[gcIndex]];
}
}

}


module.exports = Heap;
12 changes: 9 additions & 3 deletions src/tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@ class Tree {
this.value = value;
this.children = [];
}
// Adds a new Tree node with the input value to the current Tree node
// Adds a new Tree node with the input value to the current Tree node
addChild(value) {

const newChild = new Tree(value);
this.children.push(newChild);
}
// Checks this node's children to see if any of them matches the given value
// Continues recursively until the value has been found or all of the children
// have been checked
// CC - This can also use forEach and call recursively.
contains(value) {

if (this.value === value) return true;
for (let i = 0; i < this.children.length; i++) {
if (this.children[i].contains(value)) return true;
}
return false;
}
}

Expand Down
Loading