Explore various types of graphs, including simple, weighted, unweighted, directed, undirected, cyclic, acyclic, connected, disconnected, bipartite, and complete graphs. Understand their characteristics, applications, and how to implement them in JavaScript.
Graphs are fundamental structures in computer science, used to model pairwise relations between objects. Understanding the different types of graphs is crucial for selecting the right graph structure for a given problem. In this section, we will explore various classifications of graphs, their characteristics, and practical applications. We will also provide JavaScript code examples to illustrate how these graphs can be implemented.
A simple graph is an undirected graph that does not contain any loops (edges connected at both ends to the same vertex) or multiple edges between the same pair of vertices. Simple graphs are the most basic form of graphs and are often used in theoretical studies.
Consider a graph representing a social network where each node is a person and each edge is a friendship. In a simple graph, each friendship is represented only once.
graph TD Alice[👩💼 Alice] -- "Friends with" --> Bob[👨💼 Bob] Bob -- "Friends with" --> Carol[👩🎤 Carol] Carol -- "Friends with" --> David[👨🔧 David] David -- "Friends with" --> Alice Alice -- "Friends with" --> Carol class Alice,Bob,Carol,David person;
In a weighted graph, each edge has an associated weight or cost. These weights can represent various metrics such as distance, cost, or capacity. Weighted graphs are widely used in scenarios where the cost of traversing an edge is significant.
A map where cities are nodes and roads are edges with distances as weights.
flowchart TD %% Nodes with Descriptive Labels NewYork["🗽 New York"] Boston["🐟 Boston"] Chicago["🌆 Chicago"] Denver["⛰️ Denver"] %% Edges with Distance Weights NewYork -->|5 miles| Boston Boston -->|3 miles| Chicago Chicago --> |4 miles| Denver Denver -->|2 miles| NewYork NewYork -->|7 miles| Chicago
class WeightedGraph {
constructor() {
this.adjacencyList = {};
}
addVertex(vertex) {
if (!this.adjacencyList[vertex]) this.adjacencyList[vertex] = [];
}
addEdge(vertex1, vertex2, weight) {
this.adjacencyList[vertex1].push({ node: vertex2, weight });
this.adjacencyList[vertex2].push({ node: vertex1, weight });
}
}
const graph = new WeightedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addEdge('A', 'B', 5);
An unweighted graph is a graph where all edges are considered equal, meaning they do not have weights. These graphs are useful when the relationship between nodes is binary (exists or not) without any additional cost or distance.
A network of computers where each connection is equally significant.
graph TD %% Styling Nodes and Edges classDef computer fill:#bbf,stroke:#333,stroke-width:2px; %% Nodes Representing Computers compA[💻 Computer A] compB[💻 Computer B] compC[💻 Computer C] compD[💻 Computer D] %% Edges Representing Connections compA -- Connection --- compB compB -- Connection --- compC compC -- Connection --- compD compD -- Connection --- compA compA -- Connection --- compC %% Apply Classes to Nodes class compA,compB,compC,compD computer
A directed graph or digraph is a graph where edges have a direction, indicating a one-way relationship. Directed graphs are essential for modeling scenarios where relationships are not mutual.
A website’s hyperlink structure where each page links to another.
graph TD; A --> B; B --> C; C --> D; D --> A; A --> C;
class DirectedGraph {
constructor() {
this.adjacencyList = {};
}
addVertex(vertex) {
if (!this.adjacencyList[vertex]) this.adjacencyList[vertex] = [];
}
addEdge(vertex1, vertex2) {
this.adjacencyList[vertex1].push(vertex2);
}
}
const digraph = new DirectedGraph();
digraph.addVertex('A');
digraph.addVertex('B');
digraph.addEdge('A', 'B');
An undirected graph is a graph where edges have no direction, indicating a mutual relationship between nodes. These graphs are suitable for modeling scenarios where relationships are bidirectional.
A friendship network where each friendship is mutual.
graph TD %% Nodes Representing People Alice["👩 Alice"] Bob["👨 Bob"] Carol["👩 Carol"] David["👨 David"] %% Bidirectional Edges Representing Mutual Friendships Alice <--> Bob Bob <--> Carol Carol <--> David David <--> Alice Alice <--> Carol %% Optional: Apply Styling to Nodes (classDef not utilized as specific styling is not mandatory here) classDef person fill:#e0f7fa,stroke:#333,stroke-width:2px class Alice,Bob,Carol,David person
A cyclic graph contains at least one cycle, which is a path that starts and ends at the same vertex without repeating any edges or vertices. Cyclic graphs are common in network topology and circuit design.
A network with redundant paths to ensure connectivity.
graph TD %% Nodes Representing Network Points NodeA[Node A] NodeB[Node B] NodeC[Node C] NodeD[Node D] %% Edges Representing Redundant Pathways NodeA --> NodeB NodeB --> NodeC NodeC --> NodeA NodeC --> NodeD NodeA -.-> NodeD NodeB -.-> NodeD NodeB -.-> NodeA
An acyclic graph is a graph that contains no cycles. In directed graphs, these are known as Directed Acyclic Graphs (DAGs) and are often used in scheduling and dependency resolution.
A project task dependency graph where tasks must be completed in a specific order.
graph TD %% Task Nodes Start["🏁 Start"] TaskA["🔨 Task A: Initial Setup"] TaskB["📋 Task B: Data Collection"] TaskC["🛠️ Task C: Data Processing"] TaskD["✅ Task D: Final Review"] End["🏆 End"] %% Task Dependencies Start --> TaskA TaskA --> TaskB TaskB --> TaskC TaskC --> TaskD TaskD --> End
A connected graph is an undirected graph where there is a path between every pair of vertices. Connected graphs are crucial for ensuring that all nodes in a network can communicate with each other.
A fully connected network where each computer can reach any other.
graph TD %% Nodes Representing Computers compA[💻 Computer A] compB[💻 Computer B] compC[💻 Computer C] compD[💻 Computer D] %% Fully Connected Network Edges compA --> compB compA --> compC compA --> compD compB --> compC compB --> compD compC --> compD
A disconnected graph contains at least one pair of vertices without a path connecting them. These graphs are useful for modeling isolated clusters within a network.
A network with multiple isolated subnetworks.
graph TD %% Cluster 1 A["Node A"] B["Node B"] %% Cluster 2 C["Node C"] D["Node D"] %% Connections within Clusters A --- B C --- D %% Styling for Clarity classDef cluster fill:#f0f0f0,stroke:#333,stroke-width:2px,fill-opacity:0.5; class A,B,C,D cluster;
A bipartite graph is a graph whose vertices can be divided into two disjoint sets such that every edge connects a vertex from one set to another. Bipartite graphs are used in matching problems and network flow algorithms.
A job assignment scenario where jobs and applicants are two sets.
graph TD %% Define Subgraphs with Distinct Sets subgraph Jobs direction TB JobA["Job A"] JobB["Job B"] end subgraph Applicants direction TB ApplicantC["Applicant C"] ApplicantD["Applicant D"] end %% Edges Representing Possible Assignments JobA -- "applies to" --> ApplicantC JobB -- "applies to" --> ApplicantD JobA -- "applies to" --> ApplicantD %% Optional Styling for Clarity classDef jobStyle fill:#f0e68c,stroke:#333,stroke-width:2px; classDef applicantStyle fill:#add8e6,stroke:#333,stroke-width:2px; class JobA,JobB jobStyle; class ApplicantC,ApplicantD applicantStyle;
class BipartiteGraph {
constructor() {
this.set1 = new Set();
this.set2 = new Set();
this.edges = [];
}
addVertexToSet1(vertex) {
this.set1.add(vertex);
}
addVertexToSet2(vertex) {
this.set2.add(vertex);
}
addEdge(vertex1, vertex2) {
if (this.set1.has(vertex1) && this.set2.has(vertex2)) {
this.edges.push([vertex1, vertex2]);
}
}
}
const bipartiteGraph = new BipartiteGraph();
bipartiteGraph.addVertexToSet1('Job1');
bipartiteGraph.addVertexToSet2('Applicant1');
bipartiteGraph.addEdge('Job1', 'Applicant1');
A complete graph is a graph where every pair of distinct vertices is connected by a unique edge. Complete graphs are used in scenarios where every node needs to be directly connected to every other node.
A fully connected mesh network.
graph TD %% Nodes Representing Network Points nodeA["Node A"] nodeB["Node B"] nodeC["Node C"] nodeD["Node D"] %% Complete Graph: Every Node Connects to Every Other Node nodeA --- nodeB nodeA --- nodeC nodeA ---> nodeD nodeB --- nodeC nodeB --- nodeD nodeC --- nodeD
Graphs are versatile structures with numerous real-world applications:
To gain a deeper understanding of graphs, experiment by modifying existing graphs and observing how their classification changes. For instance, add or remove edges to see how a graph transitions from connected to disconnected, or introduce weights to transform an unweighted graph into a weighted one.
Understanding the various types of graphs and their characteristics is essential for effectively modeling complex relationships and solving problems in computer science. By leveraging JavaScript to implement these graphs, you can experiment with different structures and gain practical insights into their applications.