Skip to content

Commit eb4bf63

Browse files
Haraman Johalcasellimarcosiriakgithub-actions
authored
Add undirected and directed graphs (rust-lang#180)
Co-authored-by: Marco Caselli <[email protected]> Co-authored-by: Andrii Siriak <[email protected]> Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
1 parent 431a537 commit eb4bf63

File tree

3 files changed

+224
-0
lines changed

3 files changed

+224
-0
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* Data Structures
1010
* [B Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/b_tree.rs)
1111
* [Binary Search Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/binary_search_tree.rs)
12+
* [Graph](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/graph.rs)
1213
* [Heap](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/heap.rs)
1314
* [Linked List](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/linked_list.rs)
1415
* Dynamic Programming

src/data_structures/graph.rs

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
use std::collections::{HashMap, HashSet};
2+
use std::fmt;
3+
4+
#[derive(Debug, Clone)]
5+
pub struct NodeNotInGraph;
6+
7+
impl fmt::Display for NodeNotInGraph {
8+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
9+
write!(f, "accessing a node that is not in the graph")
10+
}
11+
}
12+
13+
pub struct DirectedGraph {
14+
adjacency_table: HashMap<String, Vec<(String, i32)>>,
15+
}
16+
17+
impl Graph for DirectedGraph {
18+
fn new() -> DirectedGraph {
19+
DirectedGraph {
20+
adjacency_table: HashMap::new(),
21+
}
22+
}
23+
fn adjacency_table_mutable(&mut self) -> &mut HashMap<String, Vec<(String, i32)>> {
24+
&mut self.adjacency_table
25+
}
26+
fn adjacency_table(&self) -> &HashMap<String, Vec<(String, i32)>> {
27+
&self.adjacency_table
28+
}
29+
}
30+
31+
pub struct UndirectedGraph {
32+
adjacency_table: HashMap<String, Vec<(String, i32)>>,
33+
}
34+
35+
impl Graph for UndirectedGraph {
36+
fn new() -> UndirectedGraph {
37+
UndirectedGraph {
38+
adjacency_table: HashMap::new(),
39+
}
40+
}
41+
fn adjacency_table_mutable(&mut self) -> &mut HashMap<String, Vec<(String, i32)>> {
42+
&mut self.adjacency_table
43+
}
44+
fn adjacency_table(&self) -> &HashMap<String, Vec<(String, i32)>> {
45+
&self.adjacency_table
46+
}
47+
fn add_edge(&mut self, edge: (&str, &str, i32)) {
48+
self.add_node(edge.0);
49+
self.add_node(edge.1);
50+
51+
self.adjacency_table
52+
.entry(edge.0.to_string())
53+
.and_modify(|e| {
54+
e.push((edge.1.to_string(), edge.2));
55+
});
56+
self.adjacency_table
57+
.entry(edge.1.to_string())
58+
.and_modify(|e| {
59+
e.push((edge.0.to_string(), edge.2));
60+
});
61+
}
62+
}
63+
64+
pub trait Graph {
65+
fn new() -> Self;
66+
fn adjacency_table_mutable(&mut self) -> &mut HashMap<String, Vec<(String, i32)>>;
67+
fn adjacency_table(&self) -> &HashMap<String, Vec<(String, i32)>>;
68+
69+
fn add_node(&mut self, node: &str) -> bool {
70+
match self.adjacency_table().get(node) {
71+
None => {
72+
self.adjacency_table_mutable()
73+
.insert((*node).to_string(), Vec::new());
74+
true
75+
}
76+
_ => false,
77+
}
78+
}
79+
80+
fn add_edge(&mut self, edge: (&str, &str, i32)) {
81+
self.add_node(edge.0);
82+
self.add_node(edge.1);
83+
84+
self.adjacency_table_mutable()
85+
.entry(edge.0.to_string())
86+
.and_modify(|e| {
87+
e.push((edge.1.to_string(), edge.2));
88+
});
89+
}
90+
91+
fn neighbours(&self, node: &str) -> Result<&Vec<(String, i32)>, NodeNotInGraph> {
92+
match self.adjacency_table().get(node) {
93+
None => Err(NodeNotInGraph),
94+
Some(i) => Ok(i),
95+
}
96+
}
97+
98+
fn contains(&self, node: &str) -> bool {
99+
self.adjacency_table().get(node).is_some()
100+
}
101+
102+
fn nodes(&self) -> HashSet<&String> {
103+
self.adjacency_table().keys().collect()
104+
}
105+
106+
fn edges(&self) -> Vec<(&String, &String, i32)> {
107+
let mut edges = Vec::new();
108+
for (from_node, from_node_neighbours) in self.adjacency_table() {
109+
for (to_node, weight) in from_node_neighbours {
110+
edges.push((from_node, to_node, *weight));
111+
}
112+
}
113+
edges
114+
}
115+
}
116+
117+
#[cfg(test)]
118+
mod test_undirected_graph {
119+
use super::Graph;
120+
use super::UndirectedGraph;
121+
#[test]
122+
fn test_add_edge() {
123+
let mut graph = UndirectedGraph::new();
124+
125+
graph.add_edge(("a", "b", 5));
126+
graph.add_edge(("b", "c", 10));
127+
graph.add_edge(("c", "a", 7));
128+
129+
let expected_edges = [
130+
(&String::from("a"), &String::from("b"), 5),
131+
(&String::from("b"), &String::from("a"), 5),
132+
(&String::from("c"), &String::from("a"), 7),
133+
(&String::from("a"), &String::from("c"), 7),
134+
(&String::from("b"), &String::from("c"), 10),
135+
(&String::from("c"), &String::from("b"), 10),
136+
];
137+
for edge in expected_edges.iter() {
138+
assert_eq!(graph.edges().contains(edge), true);
139+
}
140+
}
141+
142+
#[test]
143+
fn test_neighbours() {
144+
let mut graph = UndirectedGraph::new();
145+
146+
graph.add_edge(("a", "b", 5));
147+
graph.add_edge(("b", "c", 10));
148+
graph.add_edge(("c", "a", 7));
149+
150+
assert_eq!(
151+
graph.neighbours("a").unwrap(),
152+
&vec![(String::from("b"), 5), (String::from("c"), 7)]
153+
);
154+
}
155+
}
156+
157+
#[cfg(test)]
158+
mod test_directed_graph {
159+
use super::DirectedGraph;
160+
use super::Graph;
161+
162+
#[test]
163+
fn test_add_node() {
164+
let mut graph = DirectedGraph::new();
165+
graph.add_node("a");
166+
graph.add_node("b");
167+
graph.add_node("c");
168+
assert_eq!(
169+
graph.nodes(),
170+
[&String::from("a"), &String::from("b"), &String::from("c")]
171+
.iter()
172+
.cloned()
173+
.collect()
174+
);
175+
}
176+
177+
#[test]
178+
fn test_add_edge() {
179+
let mut graph = DirectedGraph::new();
180+
181+
graph.add_edge(("a", "b", 5));
182+
graph.add_edge(("c", "a", 7));
183+
graph.add_edge(("b", "c", 10));
184+
185+
let expected_edges = [
186+
(&String::from("a"), &String::from("b"), 5),
187+
(&String::from("c"), &String::from("a"), 7),
188+
(&String::from("b"), &String::from("c"), 10),
189+
];
190+
for edge in expected_edges.iter() {
191+
assert_eq!(graph.edges().contains(edge), true);
192+
}
193+
}
194+
195+
#[test]
196+
fn test_neighbours() {
197+
let mut graph = DirectedGraph::new();
198+
199+
graph.add_edge(("a", "b", 5));
200+
graph.add_edge(("b", "c", 10));
201+
graph.add_edge(("c", "a", 7));
202+
203+
assert_eq!(
204+
graph.neighbours("a").unwrap(),
205+
&vec![(String::from("b"), 5)]
206+
);
207+
}
208+
209+
#[test]
210+
fn test_contains() {
211+
let mut graph = DirectedGraph::new();
212+
graph.add_node("a");
213+
graph.add_node("b");
214+
graph.add_node("c");
215+
assert_eq!(graph.contains("a"), true);
216+
assert_eq!(graph.contains("b"), true);
217+
assert_eq!(graph.contains("c"), true);
218+
assert_eq!(graph.contains("d"), false);
219+
}
220+
}

src/data_structures/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
mod b_tree;
22
mod binary_search_tree;
3+
mod graph;
34
mod heap;
45
mod linked_list;
56

67
pub use self::b_tree::BTree;
78
pub use self::binary_search_tree::BinarySearchTree;
9+
pub use self::graph::DirectedGraph;
10+
pub use self::graph::UndirectedGraph;
811
pub use self::heap::{Heap, MaxHeap, MinHeap};
912
pub use self::linked_list::LinkedList;

0 commit comments

Comments
 (0)