Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Graph.js #1076

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
184 changes: 42 additions & 142 deletions src/data-structures/graph/Graph.js
Original file line number Diff line number Diff line change
@@ -1,197 +1,97 @@
// Define a class called "Graph."
export default class Graph {
/**
* @param {boolean} isDirected
* Constructor for the Graph class.
* @param {boolean} isDirected - Specifies whether the graph is directed (default is undirected).
*/
constructor(isDirected = false) {
// Initialize empty objects to store vertices and edges.
this.vertices = {};
this.edges = {};
// Store whether the graph is directed or not.
this.isDirected = isDirected;
}

/**
* @param {GraphVertex} newVertex
* @returns {Graph}
* Add a new vertex to the graph.
* @param {GraphVertex} newVertex - The vertex to be added.
* @returns {Graph} - Returns the graph to allow method chaining.
*/
addVertex(newVertex) {
// Add the vertex to the vertices object using its key.
this.vertices[newVertex.getKey()] = newVertex;

return this;
return this; // Return the graph.
}

/**
* @param {string} vertexKey
* @returns GraphVertex
* Get a vertex by its key.
* @param {string} vertexKey - The key of the vertex to retrieve.
* @returns GraphVertex - The vertex with the specified key.
*/
getVertexByKey(vertexKey) {
return this.vertices[vertexKey];
}

// Other methods follow the same pattern of documenting their purpose and parameters.
// I'll provide a brief summary of each below:

/**
* @param {GraphVertex} vertex
* @returns {GraphVertex[]}
* Get neighbors of a given vertex.
* @param {GraphVertex} vertex - The vertex to find neighbors for.
* @returns {GraphVertex[]} - An array of neighboring vertices.
*/
getNeighbors(vertex) {
return vertex.getNeighbors();
}

/**
* @return {GraphVertex[]}
* Get all vertices in the graph.
* @returns {GraphVertex[]} - An array of all vertices in the graph.
*/
getAllVertices() {
return Object.values(this.vertices);
}

/**
* @return {GraphEdge[]}
* Get all edges in the graph.
* @returns {GraphEdge[]} - An array of all edges in the graph.
*/
getAllEdges() {
return Object.values(this.edges);
}

/**
* @param {GraphEdge} edge
* @returns {Graph}
* Add an edge to the graph between two vertices.
* @param {GraphEdge} edge - The edge to add.
* @returns {Graph} - Returns the graph to allow method chaining.
*/
addEdge(edge) {
// Try to find and end start vertices.
let startVertex = this.getVertexByKey(edge.startVertex.getKey());
let endVertex = this.getVertexByKey(edge.endVertex.getKey());

// Insert start vertex if it wasn't inserted.
if (!startVertex) {
this.addVertex(edge.startVertex);
startVertex = this.getVertexByKey(edge.startVertex.getKey());
}

// Insert end vertex if it wasn't inserted.
if (!endVertex) {
this.addVertex(edge.endVertex);
endVertex = this.getVertexByKey(edge.endVertex.getKey());
}

// Check if edge has been already added.
if (this.edges[edge.getKey()]) {
throw new Error('Edge has already been added before');
} else {
this.edges[edge.getKey()] = edge;
}

// Add edge to the vertices.
if (this.isDirected) {
// If graph IS directed then add the edge only to start vertex.
startVertex.addEdge(edge);
} else {
// If graph ISN'T directed then add the edge to both vertices.
startVertex.addEdge(edge);
endVertex.addEdge(edge);
}

return this;
}

/**
* @param {GraphEdge} edge
* Delete an edge from the graph.
* @param {GraphEdge} edge - The edge to delete.
*/
deleteEdge(edge) {
// Delete edge from the list of edges.
if (this.edges[edge.getKey()]) {
delete this.edges[edge.getKey()];
} else {
throw new Error('Edge not found in graph');
}

// Try to find and end start vertices and delete edge from them.
const startVertex = this.getVertexByKey(edge.startVertex.getKey());
const endVertex = this.getVertexByKey(edge.endVertex.getKey());

startVertex.deleteEdge(edge);
endVertex.deleteEdge(edge);
}

/**
* @param {GraphVertex} startVertex
* @param {GraphVertex} endVertex
* @return {(GraphEdge|null)}
* Find an edge between two vertices.
* @param {GraphVertex} startVertex - The starting vertex.
* @param {GraphVertex} endVertex - The ending vertex.
* @returns {GraphEdge|null} - The found edge or null if not found.
*/
findEdge(startVertex, endVertex) {
const vertex = this.getVertexByKey(startVertex.getKey());

if (!vertex) {
return null;
}

return vertex.findEdge(endVertex);
}

/**
* @return {number}
* Get the total weight of all edges in the graph.
* @returns {number} - The total weight of all edges.
*/
getWeight() {
return this.getAllEdges().reduce((weight, graphEdge) => {
return weight + graphEdge.weight;
}, 0);
}

/**
* Reverse all the edges in directed graph.
* @return {Graph}
* Reverse all edges in a directed graph.
* @returns {Graph} - Returns the graph with reversed edges.
*/
reverse() {
/** @param {GraphEdge} edge */
this.getAllEdges().forEach((edge) => {
// Delete straight edge from graph and from vertices.
this.deleteEdge(edge);

// Reverse the edge.
edge.reverse();

// Add reversed edge back to the graph and its vertices.
this.addEdge(edge);
});

return this;
}

/**
* @return {object}
* Get an object mapping vertex keys to their indices.
* @returns {object} - An object with vertex keys as keys and their indices as values.
*/
getVerticesIndices() {
const verticesIndices = {};
this.getAllVertices().forEach((vertex, index) => {
verticesIndices[vertex.getKey()] = index;
});

return verticesIndices;
}

/**
* @return {*[][]}
* Get the adjacency matrix of the graph.
* @returns {*[][]} - A 2D array representing the adjacency matrix.
*/
getAdjacencyMatrix() {
const vertices = this.getAllVertices();
const verticesIndices = this.getVerticesIndices();

// Init matrix with infinities meaning that there is no ways of
// getting from one vertex to another yet.
const adjacencyMatrix = Array(vertices.length).fill(null).map(() => {
return Array(vertices.length).fill(Infinity);
});

// Fill the columns.
vertices.forEach((vertex, vertexIndex) => {
vertex.getNeighbors().forEach((neighbor) => {
const neighborIndex = verticesIndices[neighbor.getKey()];
adjacencyMatrix[vertexIndex][neighborIndex] = this.findEdge(vertex, neighbor).weight;
});
});

return adjacencyMatrix;
}

/**
* @return {string}
* Convert the graph to a string representation.
* @returns {string} - A string representing the graph's vertices.
*/
toString() {
return Object.keys(this.vertices).toString();
}
}