add graph! macro and vertex/edge_count

This commit is contained in:
mxhagen 2025-02-16 19:25:00 +01:00
parent 925370481c
commit 14a3342f60
2 changed files with 50 additions and 26 deletions

View File

@ -4,7 +4,7 @@ use std::{
}; };
pub struct Graph<V> { pub struct Graph<V> {
pub vertices: Vec<V>, pub vertices: HashSet<V>,
pub edges: HashMap<V, Vec<V>>, pub edges: HashMap<V, Vec<V>>,
} }
@ -12,6 +12,16 @@ impl<V> Graph<V>
where where
V: Eq + Hash + Ord + Clone, V: Eq + Hash + Ord + Clone,
{ {
/// get the number of vertices of the graph
pub fn vertex_count(&self) -> usize {
self.vertices.len()
}
/// get the number of edges of the graph
pub fn edge_count(&self) -> usize {
self.edges.values().map(Vec::len).sum()
}
/// check if an edge is contained in the graph /// check if an edge is contained in the graph
/// (only checks the provided direction) /// (only checks the provided direction)
pub fn has_edge(&self, edge: (&V, &V)) -> bool { pub fn has_edge(&self, edge: (&V, &V)) -> bool {
@ -49,8 +59,7 @@ where
q.push_back(vec![from]); q.push_back(vec![from]);
visited.insert(from); visited.insert(from);
while !q.is_empty() { while let Some(mut path) = q.pop_front() {
let mut path = q.pop_front().unwrap();
let current = path.last().unwrap(); let current = path.last().unwrap();
for neighbor in self.neighbors(current) { for neighbor in self.neighbors(current) {
@ -81,8 +90,7 @@ where
q.push(vec![from]); q.push(vec![from]);
while !q.is_empty() { while let Some(mut path) = q.pop() {
let mut path = q.pop().unwrap();
let &current = path.last().unwrap(); let &current = path.last().unwrap();
if current == to { if current == to {
@ -103,3 +111,19 @@ where
None None
} }
} }
#[macro_export]
macro_rules! graph {
( $( $v:tt : $( $e:tt ),* );* $(;)? ) => {{
let mut edges = std::collections::HashMap::new();
let mut vertices = std::collections::HashSet::new();
$(
vertices.insert($v);
edges.insert($v, vec![$( $e ),*]);
$( vertices.insert($e); )*
)*
Graph { vertices, edges }
}};
}

View File

@ -1,5 +1,3 @@
use std::collections::HashMap;
mod graph; mod graph;
pub use graph::Graph; pub use graph::Graph;
@ -9,24 +7,18 @@ fn main() {
// -> 0 ┃ 3 // -> 0 ┃ 3
// ┗━━━━━2━━━━━┛ // ┗━━━━━2━━━━━┛
let vs = vec![0, 1, 2, 3]; let g = graph! {
let es = HashMap::from([ 0: 1, 2;
(0, vec![1, 2]), 1: 0, 2, 3;
(1, vec![0, 2, 3]), 2: 0, 1, 3;
(2, vec![0, 1, 3]), 3: 1, 2;
(3, vec![1, 2]),
]);
let g = Graph {
vertices: vs.clone(),
edges: es.clone(),
}; };
for v in &vs { for v in &g.vertices {
assert!(g.has_vertex(v), "G should contain vertex {v}"); assert!(g.has_vertex(v), "G should contain vertex {v}");
} }
for (a, neighbors) in &es { for (a, neighbors) in &g.edges {
for b in neighbors { for b in neighbors {
assert!(g.has_edge((a, b)), "G should contain edge ({a}, {b})"); assert!(g.has_edge((a, b)), "G should contain edge ({a}, {b})");
assert!( assert!(
@ -36,19 +28,27 @@ fn main() {
} }
} }
for i in 0..vs.len() { let n = g.vertex_count();
for j in i + 1..vs.len() { let vs = g.vertices.iter().collect::<Vec<_>>();
for i in 0..n {
for j in i + 1..n {
let (a, b) = (vs[i], vs[j]); let (a, b) = (vs[i], vs[j]);
let shortest_path_length = match (a, b) { let shortest_path_length = match (a, b) {
(0, 3) | (3, 0) => 3, (0, 3) | (3, 0) => 3,
_ => 2, _ => 2,
}; };
let path = g.find_path_dfs(&a, &b); let path = g.find_path_dfs(a, b);
assert!(path.is_some(), "Path from {a} to {b} should be found in G with dfs"); assert!(
path.is_some(),
"Path from {a} to {b} should be found in G with dfs"
);
let path = g.find_path_bfs(&a, &b); let path = g.find_path_bfs(a, b);
assert!(path.is_some(), "Path from {a} to {b} should be found in G with bfs"); assert!(
path.is_some(),
"Path from {a} to {b} should be found in G with bfs"
);
let path = path.unwrap(); let path = path.unwrap();
assert_eq!( assert_eq!(