add iter implementation
use HashSet for adjacency list instead of Vec correct graph! macro for edge cases
This commit is contained in:
parent
14a3342f60
commit
bd416fcf70
64
src/graph.rs
64
src/graph.rs
@ -3,14 +3,18 @@ use std::{
|
|||||||
hash::Hash,
|
hash::Hash,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub trait VertexType: Eq + Hash + Ord + Clone {}
|
||||||
|
|
||||||
|
impl<T> VertexType for T where T: Eq + Hash + Ord + Clone {}
|
||||||
|
|
||||||
pub struct Graph<V> {
|
pub struct Graph<V> {
|
||||||
pub vertices: HashSet<V>,
|
pub vertices: HashSet<V>,
|
||||||
pub edges: HashMap<V, Vec<V>>,
|
pub edges: HashMap<V, HashSet<V>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Graph<V>
|
impl<V> Graph<V>
|
||||||
where
|
where
|
||||||
V: Eq + Hash + Ord + Clone,
|
V: VertexType,
|
||||||
{
|
{
|
||||||
/// get the number of vertices of the graph
|
/// get the number of vertices of the graph
|
||||||
pub fn vertex_count(&self) -> usize {
|
pub fn vertex_count(&self) -> usize {
|
||||||
@ -19,7 +23,7 @@ where
|
|||||||
|
|
||||||
/// get the number of edges of the graph
|
/// get the number of edges of the graph
|
||||||
pub fn edge_count(&self) -> usize {
|
pub fn edge_count(&self) -> usize {
|
||||||
self.edges.values().map(Vec::len).sum()
|
self.edges.values().map(HashSet::len).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// check if an edge is contained in the graph
|
/// check if an edge is contained in the graph
|
||||||
@ -43,10 +47,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// get a slice containing all neighbors of the edge
|
/// get a slice containing all neighbors of the edge
|
||||||
pub fn neighbors(&self, vertex: &V) -> &[V] {
|
pub fn neighbors(&self, vertex: &V) -> Vec<&V> {
|
||||||
self.edges
|
self.edges
|
||||||
.get(vertex)
|
.get(vertex)
|
||||||
.map(Vec::as_slice)
|
.map(|es| es.iter().collect())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +102,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
for neighbor in self.neighbors(current).iter().rev() {
|
for neighbor in self.neighbors(current).iter().rev() {
|
||||||
if path.contains(&neighbor) {
|
if path.contains(neighbor) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +114,44 @@ where
|
|||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &V> {
|
||||||
|
self.vertices.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V> IntoIterator for Graph<V>
|
||||||
|
where
|
||||||
|
V: VertexType,
|
||||||
|
{
|
||||||
|
type Item = V;
|
||||||
|
type IntoIter = IntoIter<V>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
let items = self.vertices.into_iter().collect::<Vec<_>>().clone();
|
||||||
|
IntoIter { items, i: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IntoIter<V> {
|
||||||
|
items: Vec<V>,
|
||||||
|
i: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V> Iterator for IntoIter<V>
|
||||||
|
where
|
||||||
|
V: VertexType,
|
||||||
|
{
|
||||||
|
type Item = V;
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self.items.get(self.i) {
|
||||||
|
None => None,
|
||||||
|
item => {
|
||||||
|
self.i += 1;
|
||||||
|
item.cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
@ -119,8 +161,14 @@ macro_rules! graph {
|
|||||||
let mut vertices = std::collections::HashSet::new();
|
let mut vertices = std::collections::HashSet::new();
|
||||||
|
|
||||||
$(
|
$(
|
||||||
vertices.insert($v);
|
vertices.insert($v); // insert vertex
|
||||||
edges.insert($v, vec![$( $e ),*]);
|
let v_neighbors = std::collections::HashSet::from([
|
||||||
|
$( $e ),*
|
||||||
|
]);
|
||||||
|
|
||||||
|
edges.entry($v).or_insert(v_neighbors); // initialize its edges
|
||||||
|
|
||||||
|
// insert vertices with no outgoing edges
|
||||||
$( vertices.insert($e); )*
|
$( vertices.insert($e); )*
|
||||||
)*
|
)*
|
||||||
|
|
||||||
|
|||||||
16
src/main.rs
16
src/main.rs
@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
mod graph;
|
mod graph;
|
||||||
pub use graph::Graph;
|
pub use graph::Graph;
|
||||||
|
|
||||||
@ -7,6 +9,7 @@ fn main() {
|
|||||||
// -> 0 ┃ 3
|
// -> 0 ┃ 3
|
||||||
// ┗━━━━━2━━━━━┛
|
// ┗━━━━━2━━━━━┛
|
||||||
|
|
||||||
|
// adjacency list
|
||||||
let g = graph! {
|
let g = graph! {
|
||||||
0: 1, 2;
|
0: 1, 2;
|
||||||
1: 0, 2, 3;
|
1: 0, 2, 3;
|
||||||
@ -14,10 +17,13 @@ fn main() {
|
|||||||
3: 1, 2;
|
3: 1, 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// vertices
|
||||||
for v in &g.vertices {
|
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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// edges
|
||||||
for (a, neighbors) in &g.edges {
|
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})");
|
||||||
@ -28,6 +34,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// dfs, bfs
|
||||||
let n = g.vertex_count();
|
let n = g.vertex_count();
|
||||||
let vs = g.vertices.iter().collect::<Vec<_>>();
|
let vs = g.vertices.iter().collect::<Vec<_>>();
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
@ -58,5 +66,13 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// iterator implementation
|
||||||
|
let all_vs = g.vertices.clone();
|
||||||
|
let seen = g.into_iter().collect::<HashSet<_>>();
|
||||||
|
assert_eq!(seen, all_vs, "Iterating G should yield all vertices");
|
||||||
|
|
||||||
|
|
||||||
|
// yay
|
||||||
println!("All tests passed.");
|
println!("All tests passed.");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user