Complete Graph Class in Javascript

This article presents a comprehensive Graph class implementation in JavaScript with various graph algorithms including traversal, shortest path, and minimum spanning tree algorithms.

Graph Class Structure

The Graph class uses an adjacency list representation with two main properties:

  • nodes - Array storing all graph vertices
  • edges - Object mapping each node to its connected neighbors with weights

Basic Graph Operations

const Queue = require("./Queue");
const Stack = require("./Stack");
const PriorityQueue = require("./PriorityQueue");

class Graph {
   constructor() {
      this.edges = {};
      this.nodes = [];
   }

   addNode(node) {
      this.nodes.push(node);
      this.edges[node] = [];
   }

   addEdge(node1, node2, weight = 1) {
      this.edges[node1].push({ node: node2, weight: weight });
      this.edges[node2].push({ node: node1, weight: weight });
   }

   addDirectedEdge(node1, node2, weight = 1) {
      this.edges[node1].push({ node: node2, weight: weight });
   }

   display() {
      let graph = "";
      this.nodes.forEach(node => {
         graph += node + "->" + this.edges[node].map(n => n.node).join(", ") + "<br>";
      });
      console.log(graph);
   }
}

Graph Traversal Algorithms

Breadth-First Search (BFS)

BFS(node) {
   let q = new Queue(this.nodes.length);
   let explored = new Set();
   q.enqueue(node);
   explored.add(node);
   
   while (!q.isEmpty()) {
      let t = q.dequeue();
      console.log(t);
      this.edges[t].filter(n => !explored.has(n.node)).forEach(n => {
         explored.add(n.node);
         q.enqueue(n.node);
      });
   }
}

Depth-First Search (DFS)

DFS(node) {
   let s = new Stack(this.nodes.length);
   let explored = new Set();
   s.push(node);
   explored.add(node);

   while (!s.isEmpty()) {
      let t = s.pop();
      console.log(t);

      this.edges[t].filter(n => !explored.has(n.node)).forEach(n => {
         explored.add(n.node);
         s.push(n.node);
      });
   }
}

Shortest Path Algorithms

BFS Shortest Path (Unweighted)

BFSShortestPath(n1, n2) {
   let q = new Queue(this.nodes.length);
   let explored = new Set();
   let distances = {};
   distances[n1] = 0;

   q.enqueue(n1);
   explored.add(n1);

   while (!q.isEmpty()) {
      let t = q.dequeue();
      this.edges[t].filter(n => !explored.has(n.node)).forEach(n => {
         explored.add(n.node);
         distances[n.node] = distances[t] + 1;
         q.enqueue(n.node);
      });
   }
   return distances[n2];
}

Dijkstra's Algorithm (Weighted)

dijkstraAlgorithm(startNode) {
   let distances = {};
   let prev = {};
   let pq = new PriorityQueue(this.nodes.length * this.nodes.length);

   distances[startNode] = 0;
   pq.enqueue(startNode, 0);
   
   this.nodes.forEach(node => {
      if (node !== startNode) distances[node] = Infinity;
      prev[node] = null;
   });

   while (!pq.isEmpty()) {
      let minNode = pq.dequeue();
      let currNode = minNode.data;

      this.edges[currNode].forEach(neighbor => {
         let alt = distances[currNode] + neighbor.weight;
         if (alt < distances[neighbor.node]) {
            distances[neighbor.node] = alt;
            prev[neighbor.node] = currNode;
            pq.enqueue(neighbor.node, distances[neighbor.node]);
         }
      });
   }
   return distances;
}

Minimum Spanning Tree Algorithms

Prim's Algorithm

primsMST() {
   const MST = new Graph();
   if (this.nodes.length === 0) {
      return MST;
   }

   let s = this.nodes[0];
   let edgeQueue = new PriorityQueue(this.nodes.length * this.nodes.length);
   let explored = new Set();

   explored.add(s);
   MST.addNode(s);

   this.edges[s].forEach(edge => {
      edgeQueue.enqueue([s, edge.node], edge.weight);
   });

   while (!edgeQueue.isEmpty()) {
      let currentMinEdge = edgeQueue.dequeue();
      
      while (!edgeQueue.isEmpty() && explored.has(currentMinEdge.data[1])) {
         currentMinEdge = edgeQueue.dequeue();
      }
      
      let nextNode = currentMinEdge.data[1];

      if (!explored.has(nextNode)) {
         MST.addNode(nextNode);
         MST.addEdge(currentMinEdge.data[0], nextNode, currentMinEdge.priority);
         
         this.edges[nextNode].forEach(edge => {
            edgeQueue.enqueue([nextNode, edge.node], edge.weight);
         });
         
         explored.add(nextNode);
      }
   }
   return MST;
}

Union-Find Data Structure

The UnionFind class supports Kruskal's MST algorithm by efficiently tracking connected components:

class UnionFind {
   constructor(elements) {
      this.count = elements.length;
      this.parent = {};
      elements.forEach(e => (this.parent[e] = e));
   }

   union(a, b) {
      let rootA = this.find(a);
      let rootB = this.find(b);

      if (rootA === rootB) return;

      if (rootA < rootB) {
         if (this.parent[b] != b) this.union(this.parent[b], a);
         this.parent[b] = this.parent[a];
      } else {
         if (this.parent[a] != a) this.union(this.parent[a], b);
         this.parent[a] = this.parent[b];
      }
   }

   find(a) {
      while (this.parent[a] !== a) {
         a = this.parent[a];
      }
      return a;
   }

   connected(a, b) {
      return this.find(a) === this.find(b);
   }
}

Algorithm Comparison

Algorithm Purpose Time Complexity Best For
BFS Traversal/Shortest Path O(V + E) Unweighted graphs
DFS Traversal O(V + E) Topological sorting
Dijkstra Shortest Path O((V + E) log V) Weighted graphs
Prim's MST Minimum Spanning Tree O(E log V) Dense graphs
Kruskal's MST Minimum Spanning Tree O(E log E) Sparse graphs

Conclusion

This comprehensive Graph class provides essential algorithms for graph traversal, shortest path finding, and minimum spanning tree construction. The implementation uses efficient data structures and follows standard algorithmic approaches for optimal performance in various graph operations.

Updated on: 2026-03-15T23:18:59+05:30

300 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements