๐Ÿ›๏ธ Data Structures

GraphMatrix ๐ŸŒ

Description:

A GraphMatrix represents a directed graph using an adjacency matrix where each node is connected via edges. The matrix represents the relationships between nodes, with 1 indicating an edge between two nodes and 0 meaning no edge.

Pros & Cons:

Using this data structure has several benefits:

  • Fast Edge Lookups: You can check if an edge exists between two nodes in constant time O(1).

  • Simple Representation: The graph structure is straightforward to implement and visualize as a matrix.

It also has some drawbacks:

  • Memory Usage: The adjacency matrix requires space proportional to the square of the number of nodes, O(nยฒ), which is inefficient for sparse graphs.

  • Handling Sparse Graphs: For large, sparse graphs, a different structure like adjacency lists might be more efficient.

1. Adding Nodes:

The add function inserts a new node into the graph and updates the adjacency matrix to include this new node with no initial edges.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 add(node: T) { this.nodes.push(node); this.matrix = this.matrixCreationHelper(this.nodes.length); } private matrixCreationHelper(length: number): number[][] { const newMatrix = new Array(length); for (let x = 0; x < length; x++) { newMatrix[x] = new Array(length).fill(0); } return newMatrix; }

2. Adding Edges:

The addEdge function creates a directed edge from one node to another. The adjacency matrix is updated with a 1 to indicate this edge.

0 1 2 3 4 5 6 addEdge(from: T, to: T) { const indexFrom = this.nodes.indexOf(from); const indexTo = this.nodes.indexOf(to); this.matrix[indexTo][indexFrom] = 1; }

3. Removing Edges:

The removeEdge function removes an edge between two nodes by setting the corresponding value in the matrix to 0.

0 1 2 3 4 5 6 removeEdge(from: T, to: T) { const indexFrom = this.nodes.indexOf(from); const indexTo = this.nodes.indexOf(to); this.matrix[indexTo][indexFrom] = 0; }

4. Showing All Edges:

The showEdges function displays the current state of the adjacency matrix, showing all connections between nodes.

0 1 2 3 4 5 6 7 8 9 10 11 showEdges() { console.log(` ${this.nodes.join(' ')}`); for (let y = 0; y < this.matrix.length; y++) { let row = `${this.nodes[y]} `; for (let x = 0; x < this.matrix.length; x++) { row += `${this.matrix[x][y]} `; } console.log(`${row}`); } }

4. Removing Nodes:

The remove function removes a node from the graph and adjusts the adjacency matrix by removing the row and column corresponding to the node.

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 remove(nodeToRemove: T) { const indexOfNodeToRemove = this.nodes.indexOf(nodeToRemove); this.nodes = this.nodes.filter(node => node !== nodeToRemove); this.matrix = this.matrixDeletionHelper(indexOfNodeToRemove, this.nodes.length); } private matrixDeletionHelper(index: number, length: number): number[][] { let newMatrix = this.matrix.filter((_, i) => i !== index); for (let x = 0; x < length; x++) { newMatrix[x] = (newMatrix[x] as number[]).filter((_, i) => i !== index); } return newMatrix; }

5. Checking for an Edge:

The checkEdge function checks if there is a directed edge between two nodes. It returns true if the edge exists, false otherwise.

0 1 2 3 4 5 6 checkEdge(from: T, to: T): boolean { const indexFrom = this.nodes.indexOf(from); const indexTo = this.nodes.indexOf(to); return this.matrix[indexTo][indexFrom] === 1; }

6. Removing All Edges from a Node:

The removeAllEdges function removes all outgoing edges from a specified node, setting the corresponding column in the adjacency matrix to 0.

0 1 2 3 4 5 6 7 removeAllEdges(from: T) { const indexFrom = this.nodes.indexOf(from); for (let i = 0; i < this.nodes.length; i++) { this.matrix[i][indexFrom] = 0; } }

Testing the Implementation

Let's see how this graph matrix works with some example operations:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 const matrix = new GraphMatrix<string>(); matrix.add("A"); matrix.add("B"); matrix.add("C"); matrix.add("D"); matrix.add("E"); matrix.add("F"); matrix.addEdge("A", "B"); matrix.addEdge("A", "C"); matrix.addEdge("B", "D"); matrix.addEdge("C", "D"); matrix.addEdge("D", "C"); matrix.addEdge("D", "E"); matrix.addEdge("E", "F"); matrix.showEdges(); matrix.removeAllEdges("A"); matrix.showEdges(); matrix.addEdge("A", "B"); matrix.addEdge("A", "C"); matrix.showEdges(); matrix.removeEdge("A", "B"); matrix.showEdges(); matrix.remove("D"); matrix.showEdges();

Console Output Example

This is an example of what you should see in the console:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 ** Adds nodes: A,B,C,D,E,F. ** Add edge A --> B. ** Add edge A --> C. ** Add edge B --> D. ** Add edge C --> D. ** Add edge D --> C. ** Add edge D --> E. ** Add edge E --> F. ** Show all added edges matrix. A B C D E F A 0 1 1 0 0 0 B 0 0 0 1 0 0 C 0 0 0 1 0 0 D 0 0 1 0 1 0 E 0 0 0 0 0 1 F 0 0 0 0 0 0 ** Remove all edges of A and show the edges matrix. A B C D E F A 0 0 0 0 0 0 B 0 0 0 1 0 0 C 0 0 0 1 0 0 D 0 0 1 0 1 0 E 0 0 0 0 0 1 F 0 0 0 0 0 0 ** Add edge A --> B. ** Add edge A --> C. A B C D E F A 0 1 1 0 0 0 B 0 0 0 1 0 0 C 0 0 0 1 0 0 D 0 0 1 0 1 0 E 0 0 0 0 0 1 F 0 0 0 0 0 0 ** remove edge A --> B. A B C D E F A 0 0 1 0 0 0 B 0 0 0 1 0 0 C 0 0 0 1 0 0 D 0 0 1 0 1 0 E 0 0 0 0 0 1 F 0 0 0 0 0 0 ** Remove node D. A B C E F A 0 0 1 0 0 B 0 0 0 0 0 C 0 0 0 0 0 E 0 0 0 0 1 F 0 0 0 0 0

Complete GraphMatrix Implementation

Hereโ€™s the complete implementation for the GraphMatrix class:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 export class GraphMatrix<T> { nodes: T[] = []; matrix: number[][] = []; add(node: T) { this.nodes.push(node); this.matrix = this.matrixCreationHelper(this.nodes.length); } private matrixCreationHelper(length: number): number[][] { const newMatrix = new Array(length).fill(null).map(() => new Array(length).fill(0)); return newMatrix; } remove(nodeToRemove: T) { const indexOfNodeToRemove = this.nodes.indexOf(nodeToRemove); this.nodes = this.nodes.filter(node => node !== nodeToRemove); this.matrix = this.matrixDeletionHelper(indexOfNodeToRemove, this.nodes.length); } private matrixDeletionHelper(index: number, length: number): number[][] { let newMatrix = this.matrix.filter((_, i) => i !== index); for (let x = 0; x < length; x++) { newMatrix[x] = (newMatrix[x] as number[]).filter((_, i) => i !== index); } return newMatrix; } addEdge(from: T, to: T) { const indexFrom = this.nodes.indexOf(from); const indexTo = this.nodes.indexOf(to); this.matrix[indexTo][indexFrom] = 1; } checkEdge(from: T, to: T) { const indexFrom = this.nodes.indexOf(from); const indexTo = this.nodes.indexOf(to); return this.matrix[indexTo][indexFrom] === 1; } removeAllEdges(from: T) { const indexFrom = this.nodes.indexOf(from); for (let i = 0; i < this.nodes.length; i++) { this.matrix[i][indexFrom] = 0; } } removeEdge(from: T, to: T) { const indexFrom = this.nodes.indexOf(from); const indexTo = this.nodes.indexOf(to); this.matrix[indexTo][indexFrom] = 0; } showEdges() { console.log(` ${this.nodes.join(' ')}`); for (let y = 0; y < this.matrix.length; y++) { let row = `${this.nodes[y]} `; for (let x = 0; x < this.matrix.length; x++) { row += `${this.matrix[x][y]} `; } console.log(`${row}`); } } }
๐Ÿ›๏ธ ๐Ÿงฎ ๐Ÿ“ โš›๏ธ ๐Ÿ