Graphs are powerful data structures for solving various problems. In this post, we will explore how to represent graphs and explain the problem-solving process in detail.
Definition of Graph
A graph is a data structure composed of vertices and edges, where vertices represent objects or nodes, and edges represent relationships between vertices. Graphs can be divided into directed graphs (Directed Graph) and undirected graphs (Undirected Graph).
Additionally, graphs can be weighted (Weighted Graph) or unweighted (Unweighted Graph). In weighted graphs, costs or distances are assigned to edges.
Ways to Represent Graphs
There are two main ways to represent graphs:
- Adjacency Matrix: Represent the relationships between vertices using a two-dimensional array. The size of the array is determined by the number of vertices, and the values in the matrix indicate the presence of an edge between two vertices or include weights.
- Adjacency List: Represent a list of adjacent vertices for each vertex. This method is memory efficient and advantageous for sparse graphs.
Problem: Finding Paths in a Graph
Let’s solve the following problem.
Problem Description: Given a graph with two vertices A and B, write a function to find and print all paths from A to B.
The graph is given as an adjacency list.
Example Problem
Input: graph = { 'A': ['B', 'C'], 'B': ['D'], 'C': ['D'], 'D': ['E'], 'E': [] } start = 'A' end = 'E' Output: ['A', 'B', 'D', 'E'] ['A', 'C', 'D', 'E']
Problem-Solving Process
To solve this problem, we will use the Depth-First Search (DFS) algorithm. DFS is an algorithm that explores the depth of the graph to find all possible paths.
Step 1: Define the DFS Function
First, we define a DFS function that explores all paths starting from the current vertex. This function maintains the current path as a list and stores the path when it reaches the target vertex.
function findPaths(graph, start, end, path = [], paths = []) {
path.push(start); // Add the current vertex to the path
// Save the path if the target vertex is reached
if (start === end) {
paths.push([...path]);
} else {
// Call DFS for adjacent vertices
for (const neighbor of graph[start] || []) {
findPaths(graph, neighbor, end, path, paths);
}
}
path.pop(); // Remove the current vertex from the path (backtracking)
return paths; // Return all paths
}
Step 2: Define the Graph and Input Values
Now, we define the graph along with the starting and ending vertices.
const graph = {
'A': ['B', 'C'],
'B': ['D'],
'C': ['D'],
'D': ['E'],
'E': []
};
const start = 'A';
const end = 'E';
Step 3: Execute the Function
We will execute the function to find all paths and print the results.
const allPaths = findPaths(graph, start, end);
console.log(allPaths);
Final Code
function findPaths(graph, start, end, path = [], paths = []) {
path.push(start); // Add the current vertex to the path
if (start === end) {
paths.push([...path]); // Add the path when it is complete
} else {
for (const neighbor of graph[start] || []) {
findPaths(graph, neighbor, end, path, paths); // Call DFS
}
}
path.pop(); // Backtracking
return paths; // Return all paths
}
const graph = {
'A': ['B', 'C'],
'B': ['D'],
'C': ['D'],
'D': ['E'],
'E': []
};
const start = 'A';
const end = 'E';
const allPaths = findPaths(graph, start, end);
console.log(allPaths);
Conclusion
In this post, we explained how to represent graphs using JavaScript and how to solve the path-finding problem using DFS. Understanding the essence and applications of graphs is very important as they are useful for solving various real-life problems. I hope you will develop your problem-solving skills by tackling more algorithmic problems in the future.