Skip to content

Commit 3902bef

Browse files
committed
Adding unweighted graph data structure
1 parent 28f1583 commit 3902bef

2 files changed

Lines changed: 144 additions & 0 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
require 'set'
2+
3+
##
4+
# This class aims to represent unweighted graphs
5+
# (i.e. graphs for which edges between nodes have no specific weight associated to them).
6+
#
7+
# Both directed (i.e. an edge between node U and node V does not imply an edge in the opposite direction)
8+
# and undirected graphs are supported, depending on the constructor invocation.
9+
10+
class UnweightedGraph
11+
attr_reader :nodes
12+
attr_reader :directed
13+
14+
def initialize(nodes: [], neighbors: {}, directed: true)
15+
@nodes = Set[]
16+
@neighbors = {}
17+
@directed = directed
18+
for node in nodes
19+
add_node(node)
20+
end
21+
neighbors.each do |node, neighbors|
22+
for neighbor in neighbors
23+
add_edge(node, neighbor)
24+
end
25+
end
26+
end
27+
28+
def add_node(node)
29+
if include?(node)
30+
raise ArgumentError, "node #{node} already exists in this graph!"
31+
end
32+
@nodes.add(node)
33+
@neighbors[node] = Set[]
34+
end
35+
36+
def add_edge(start_node, end_node)
37+
if has_neighbor?(start_node, end_node)
38+
raise ArgumentError, "node #{start_node} already has an edge to #{end_node} in this graph!"
39+
end
40+
@neighbors[start_node].add(end_node)
41+
@neighbors[end_node].add(start_node) unless directed
42+
end
43+
44+
def neighbors(node)
45+
unless include?(node)
46+
raise ArgumentError, "node #{node} does not exist in this graph!"
47+
end
48+
@neighbors[node]
49+
end
50+
51+
def empty?
52+
nodes.empty?
53+
end
54+
55+
def include?(node)
56+
nodes.include?(node)
57+
end
58+
59+
def has_neighbor?(start_node, end_node)
60+
neighbors(start_node).include?(end_node)
61+
end
62+
end
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
require 'minitest/autorun'
2+
require 'set'
3+
require_relative 'unweighted_graph'
4+
5+
class TestUnweightedGraph < Minitest::Test
6+
def test_directed_unweighted_graph_creation
7+
graph = UnweightedGraph.new(nodes: [:u, :v, :w], neighbors: {:u => [:v]}, directed: true)
8+
9+
assert graph.nodes.to_set == Set[:u, :v, :w]
10+
assert graph.neighbors(:u).to_set == Set[:v]
11+
assert graph.neighbors(:v).empty?
12+
assert graph.neighbors(:w).empty?
13+
end
14+
15+
def test_undirected_unweighted_graph_creation
16+
graph = UnweightedGraph.new(nodes: [:u, :v, :w], neighbors: {:u => [:v]}, directed: false)
17+
18+
assert graph.nodes.to_set == Set[:u, :v, :w]
19+
assert graph.neighbors(:u).to_set == Set[:v]
20+
assert graph.neighbors(:v).to_set == Set[:u]
21+
assert graph.neighbors(:w).empty?
22+
end
23+
24+
def test_empty_returns_true_for_empty_graph
25+
graph = UnweightedGraph.new
26+
27+
assert graph.empty?
28+
end
29+
30+
def test_empty_returns_false_for_non_empty_graph
31+
graph = UnweightedGraph.new(nodes: [:u])
32+
33+
assert !graph.empty?
34+
end
35+
36+
def test_include_returns_true_for_graph_nodes
37+
graph = UnweightedGraph.new(nodes: [:u])
38+
39+
assert graph.include?(:u)
40+
end
41+
42+
def test_include_returns_false_for_non_graph_nodes
43+
graph = UnweightedGraph.new
44+
45+
assert !graph.include?(:u)
46+
end
47+
48+
def test_has_neighbor_returns_true_for_graph_node_neighbors
49+
graph = UnweightedGraph.new(nodes: [:u, :v], neighbors: {:u => [:v]})
50+
51+
assert graph.has_neighbor?(:u, :v)
52+
end
53+
54+
def test_has_neighbor_returns_false_for_non_graph_node_neighbors
55+
graph = UnweightedGraph.new(nodes: [:u, :v])
56+
57+
assert !graph.has_neighbor?(:u, :v)
58+
end
59+
60+
def test_add_node_adds_node_to_graph
61+
graph = UnweightedGraph.new
62+
graph.add_node(:u)
63+
64+
assert graph.nodes.to_set == Set[:u]
65+
end
66+
67+
def test_add_edge_adds_edge_to_directed_unweighted_graph
68+
graph = UnweightedGraph.new(nodes: [:u, :v], directed: true)
69+
graph.add_edge(:u, :v)
70+
71+
assert graph.neighbors(:u).to_set == Set[:v]
72+
assert graph.neighbors(:v).empty?
73+
end
74+
75+
def test_add_edge_adds_edge_to_directed_unweighted_graph
76+
graph = UnweightedGraph.new(nodes: [:u, :v], directed: false)
77+
graph.add_edge(:u, :v)
78+
79+
assert graph.neighbors(:u).to_set == Set[:v]
80+
assert graph.neighbors(:v).to_set == Set[:u]
81+
end
82+
end

0 commit comments

Comments
 (0)