Open In App

How to Implement Graph in Ruby?

Graphs are basic data structures that represent the connections between different items. They are made up of edges (links) that show the connections between the entities and vertices (nodes) that represent the entities themselves. Numerous applications, such as social networks, navigation systems, routing algorithms, scheduling issues, and more, heavily rely on graphs.

What is a Graph?

A graph is a fundamental data structure used to represent relationships between entities. It consists of two main components:

  1. Vertices (Nodes): Nodes in a graph are like the different pieces or things you are focusing on. They represent the individual items or entities that you want to understand or connect in the graph. So, nodes are just the specific things or items you're dealing with in your graph.
  2. Edges (Connections): Edges in a graph are like arrows or lines that connect nodes, showing how they are related. They can be like two-way streets where the connection works both ways (undirected), or they can be like one-way streets where the connection only goes in one direction (directed). So, edges tell us how nodes are connected and whether the connection has a direction or not.

Types of Graphs

There are two main types of graphs:

1. Directed Graph

There is a one-way relationship between the connected nodes. For example, in a directed graph representing a website's link structure, if there is a link from page A to page B, it doesn't necessarily mean there's a link from page B back to page A. So, directed edges show us one-way connections between nodes, like the links on a website that point from one page to another.

2. Undirected Graph

Undirected edges in a graph are like a two-way street where traffic can flow in both directions. For instance, in a social network graph, if there is a connection between two people, it means they are friends with each other. It's like saying they have a mutual connection, without specifying who is initiating the connection.

Implementing Graphs in Ruby

There are two main ways to implement graphs in Ruby:

1. Hash-Based Adjacency List

Graphs can be implemented effectively using a hash-based adjacency list approach. Each node is stored as a key, with its adjacent nodes represented as values in an array or set.

Approach:

In this code, we are using a method called hashing to store information about connections between different points.

Example:

class Graph
  def initialize
    @nodes = Hash.new { |hash, key| hash[key] = [] }
  end

  def add_node(value)
    raise ArgumentError, "Node value cannot be nil" if value.nil?
    @nodes[value]
  end

  def add_edge(node1, node2)
    raise ArgumentError, "Nodes #{node1} and #{node2} 
    do not exist" unless @nodes[node1] && @nodes[node2]
    @nodes[node1] << node2
    
    # For undirected graphs, add the edge in the opposite 
    # direction as well
    @nodes[node2] << node1
  end

  def print_graph
    @nodes.each do |node, neighbors|
      puts "#{node} => #{neighbors.join(', ')}"
    end
  end
end

# Example usage:
graph = Graph.new
graph.add_node(1)
graph.add_node(2)
graph.add_node(3)
graph.add_edge(1, 2)
graph.add_edge(2, 3)
graph.add_edge(3, 1)

graph.print_graph

Output:

1

2. Adjacency Matrix

This method represents connections between nodes using a grid like structure. Each node corresponds to both a row and a column in a two-dimensional array.

Approach: The adjacency matrix is a grid, like a table, where the rows and columns represent different points, or nodes, in the graph.

Example:

class Graph
  def initialize(num_nodes)
    @num_nodes = num_nodes
    @matrix = Array.new(num_nodes) { Array.new(num_nodes, 0) }
  end

  def add_edge(node1, node2)
    raise ArgumentError, "Invalid nodes" unless valid_node?(node1) && 
    valid_node?(node2)
    @matrix[node1][node2] = 1
    
    # For undirected graphs
    @matrix[node2][node1] = 1 
  end

  def print_graph
    @matrix.each do |row|
      puts row.join(' ')
    end
  end

  private

  def valid_node?(node)
    node >= 0 && node < @num_nodes
  end
end

# Example usage:
graph = Graph.new(4)
graph.add_edge(0, 1)
graph.add_edge(0, 2)
graph.add_edge(1, 2)
graph.add_edge(2, 3)

graph.print_graph

Output:

2

Conclusion

Ruby allows programmers to model complex relationships between various entities in real world scenarios. By understanding the basics of graph theory and leveraging appropriate data structures and algorithms, programmers can effectively tackle a wide range of problems. Ruby's flexibility and intuitive syntax make it particularly well suited for implementing graph based solutions efficiently.

Article Tags :