diff --git a/data-structures/graph/graph.js b/data-structures/graph/graph.js new file mode 100644 index 0000000..7ccddb2 --- /dev/null +++ b/data-structures/graph/graph.js @@ -0,0 +1,67 @@ +const Dictionary = require('../dictionary/dictionary'); +const Queue = require('../queue/Queue'); + +function Graph() { + let vertices = []; + let adjList = new Dictionary(); + + this.addVertex = (v) => { + vertices.push(v); + adjList.set(v, []); + }; + + this.addEdge = (v, w) => { + adjList.get(v).push(w); + adjList.get(w).push(v); + } + + this.getEdges = (vertex) => { + return adjList.get(vertex); + }; + + //white = not visited + //grey = visited not explored + //black = completely explored + let initializeColor = () => { + let color = []; + + vertices.forEach((vertex, i) => { + color[vertices[i]] = 'white'; + }); + + return color; + }; + + //breadth-first search + this.bfs = (v, callback) => { + let color = initializeColor(), + queue = Queue(); + + queue.enqueue(v); + + while(!queue.isEmpty()) { + let u = queue.dequeue(); + let neighbors = adjList.get(u); + + color[u] = 'grey'; + + for (let i = 0; i < neighbors.length; i++) { + let w = neighbors[i]; + + if (color[w] === 'white') { + color[w] = 'grey'; + queue.enqueue(w); + } + } + + color[u] = 'black'; + + if (callback){ + callback(u); + } + } + }; + +} + +module.exports = Graph; diff --git a/data-structures/graph/graph.test.js b/data-structures/graph/graph.test.js new file mode 100644 index 0000000..0d187a2 --- /dev/null +++ b/data-structures/graph/graph.test.js @@ -0,0 +1,85 @@ +const test = require('ava'); +const Graph = require('./graph'); + +test('add vertex', t => { + const graph = new Graph(); + + const myVertices = [ + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I' + ]; + + myVertices.forEach(vertex => { + graph.addVertex(vertex); + }); + + graph.addEdge('A', 'B'); + graph.addEdge('A', 'C'); + graph.addEdge('A', 'D'); + graph.addEdge('C', 'D'); + graph.addEdge('C', 'G'); + graph.addEdge('D', 'G'); + graph.addEdge('D', 'H'); + graph.addEdge('B', 'E'); + graph.addEdge('B', 'F'); + graph.addEdge('E', 'I'); + + t.deepEqual(graph.getEdges('A'), ['B', 'C', 'D']); +}); + +test('breadth-first traversal', t => { + const graph = new Graph(); + + const myVertices = [ + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I' + ]; + + myVertices.forEach(vertex => { + graph.addVertex(vertex); + }); + + graph.addEdge('A', 'B'); + graph.addEdge('A', 'C'); + graph.addEdge('A', 'D'); + graph.addEdge('C', 'D'); + graph.addEdge('C', 'G'); + graph.addEdge('D', 'G'); + graph.addEdge('D', 'H'); + graph.addEdge('B', 'E'); + graph.addEdge('B', 'F'); + graph.addEdge('E', 'I'); + + let result = []; + function printVertices(vertex) { + result.push(vertex) + } + + graph.bfs('A', printVertices) + + t.deepEqual(result, [ + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I' + ]) +}); diff --git a/data-structures/tree/binarytree01.js b/data-structures/tree/binarytree01.js index b712c2a..f8606fc 100644 --- a/data-structures/tree/binarytree01.js +++ b/data-structures/tree/binarytree01.js @@ -33,8 +33,6 @@ function BinarySearchTree() { } }; - this.search = (key) => {}; - const inOrderTraverseNode = (node, callback) => { if (node !== null) { inOrderTraverseNode(node.left, callback); @@ -76,7 +74,7 @@ function BinarySearchTree() { return null; } - while(node && node.left !== null) { + while (node && node.left !== null) { node = node.left; } @@ -92,7 +90,7 @@ function BinarySearchTree() { return null; } - while(node && node.right !== null) { + while (node && node.right !== null) { node = node.right; } @@ -103,7 +101,73 @@ function BinarySearchTree() { return maxNode(root); }; - this.remove = (key) => {}; + const searchNode = (node, key) => { + if (node === null) { + return false; + } + + if (key < node.key) { + return searchNode(node.left, key); + } + + if (key > node.key) { + return searchNode(node.right, key); + } + + return true; + }; + + this.search = (key) => { + return searchNode(root, key); + }; + + const removeNode = (node, key) => { + if (node === null) { + return null; + } + + if (key < node.key) { + node.left = removeNode(node.left, key); + return node; + } else if (key > node.key) { + node.right = removeNode(node.right, key); + return node; + } else { + if (node.left === null && node.right === null) { + node = null; + return node; + } + + if (node.left === null) { + node = node.right; + return node; + } + + if (node.right === null) { + node = node.left; + return node; + } + + let aux = findMinNode(node.right); + + node.key = aux.key; + node.right = removeNode(node.right, aux.key); + + return node; + } + }; + + const findMinNode = (node) => { + while(node && node.left !== null) { + node = node.left; + } + + return node; + } + + this.remove = (key) => { + root = removeNode(root, key); + }; } module.exports = BinarySearchTree; diff --git a/data-structures/tree/binarytree01.test.js b/data-structures/tree/binarytree01.test.js index 7bb1e12..3857393 100644 --- a/data-structures/tree/binarytree01.test.js +++ b/data-structures/tree/binarytree01.test.js @@ -51,3 +51,9 @@ test('min', t => { test('max', t => { t.is(tree.max(), 25); }); + +test('search', t => { + t.is(tree.search(null), false); + t.is(tree.search(1), false); + t.is(tree.search(8), true); +});