Skip to content

Commit b7d60d2

Browse files
committed
Adding weighted graph data structure
1 parent 3902bef commit b7d60d2

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
require 'set'
2+
3+
##
4+
# This class aims to represent weighted graphs
5+
# (i.e. graphs for which edges between nodes have specific weights 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 WeightedGraph
11+
attr_reader :nodes
12+
attr_reader :directed
13+
14+
def initialize(nodes: [], edges: {}, directed: true)
15+
@nodes = Set[]
16+
@edges = {}
17+
@directed = directed
18+
for node in nodes
19+
add_node(node)
20+
end
21+
edges.each do |node, edges|
22+
for neighbor, weight in edges
23+
add_edge(node, neighbor, weight)
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+
@edges[node] = {}
34+
end
35+
36+
def add_edge(start_node, end_node, weight)
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+
@edges[start_node][end_node] = weight
41+
@edges[end_node][start_node] = weight unless directed
42+
end
43+
44+
def edges(node)
45+
unless include?(node)
46+
raise ArgumentError, "node #{node} does not exist in this graph!"
47+
end
48+
@edges[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+
edges(start_node).key?(end_node)
61+
end
62+
63+
def edge_weight(start_node, end_node)
64+
edges(start_node)[end_node]
65+
end
66+
end
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
require 'minitest/autorun'
2+
require 'set'
3+
require_relative 'weighted_graph'
4+
5+
class TestWeightedGraph < Minitest::Test
6+
def test_directed_weighted_graph_creation
7+
graph = WeightedGraph.new(nodes: [:u, :v, :w], edges: {:u => [[:v, 1]]}, directed: true)
8+
9+
assert graph.nodes.to_set == Set[:u, :v, :w]
10+
assert graph.edges(:u) == {:v => 1}
11+
assert graph.edges(:v).empty?
12+
assert graph.edges(:w).empty?
13+
end
14+
15+
def test_undirected_weighted_graph_creation
16+
graph = WeightedGraph.new(nodes: [:u, :v, :w], edges: {:u => [[:v, 1]]}, directed: false)
17+
18+
assert graph.nodes.to_set == Set[:u, :v, :w]
19+
assert graph.edges(:u) == {:v => 1}
20+
assert graph.edges(:v) == {:u => 1}
21+
assert graph.edges(:w).empty?
22+
end
23+
24+
def test_empty_returns_true_for_empty_graph
25+
graph = WeightedGraph.new
26+
27+
assert graph.empty?
28+
end
29+
30+
def test_empty_returns_false_for_non_empty_graph
31+
graph = WeightedGraph.new(nodes: [:u])
32+
33+
assert !graph.empty?
34+
end
35+
36+
def test_include_returns_true_for_graph_nodes
37+
graph = WeightedGraph.new(nodes: [:u])
38+
39+
assert graph.include?(:u)
40+
end
41+
42+
def test_include_returns_false_for_non_graph_nodes
43+
graph = WeightedGraph.new
44+
45+
assert !graph.include?(:u)
46+
end
47+
48+
def test_has_neighbor_returns_true_for_graph_node_neighbors
49+
graph = WeightedGraph.new(nodes: [:u, :v], edges: {:u => [[:v, 1]]})
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 = WeightedGraph.new(nodes: [:u, :v])
56+
57+
assert !graph.has_neighbor?(:u, :v)
58+
end
59+
60+
def test_edge_weight_returns_neighbor_edge_weight
61+
graph = WeightedGraph.new(nodes: [:u, :v], edges: {:u => [[:v, 4]]})
62+
63+
assert graph.edge_weight(:u, :v) == 4
64+
end
65+
66+
def test_add_node_adds_node_to_graph
67+
graph = WeightedGraph.new
68+
graph.add_node(:u)
69+
70+
assert graph.nodes.to_set == Set[:u]
71+
end
72+
73+
def test_add_edge_adds_edge_to_directed_weighted_graph
74+
graph = WeightedGraph.new(nodes: [:u, :v], directed: true)
75+
graph.add_edge(:u, :v, 2)
76+
77+
assert graph.edges(:u) == {:v => 2}
78+
assert graph.edges(:v).empty?
79+
end
80+
81+
def test_add_edge_adds_edge_to_directed_weighted_graph
82+
graph = WeightedGraph.new(nodes: [:u, :v], directed: false)
83+
graph.add_edge(:u, :v, 2)
84+
85+
assert graph.edges(:u) == {:v => 2}
86+
assert graph.edges(:v) == {:u => 2}
87+
end
88+
end

0 commit comments

Comments
 (0)