use std::collections::{HashMap, HashSet};
pub struct SimpleGraph<T> {
nodes: HashMap<usize, T>,
edges: HashMap<usize, Vec<usize>>,
next_id: usize,
}
impl<T> SimpleGraph<T> {
pub fn new() -> Self {
Self {
nodes: HashMap::new(),
edges: HashMap::new(),
next_id: 0,
}
}
pub fn add_node(&mut self, value: T) -> usize {
let id = self.next_id;
self.nodes.insert(id, value);
self.edges.insert(id, Vec::new());
self.next_id += 1;
id
}
pub fn add_edge(&mut self, from: usize, to: usize) -> bool {
if self.nodes.contains_key(&from) && self.nodes.contains_key(&to) {
self.edges.get_mut(&from).unwrap().push(to);
true
} else {
false
}
}
pub fn get_node(&self, id: usize) -> Option<&T> {
self.nodes.get(&id)
}
pub fn neighbors(&self, id: usize) -> Option<&Vec<usize>> {
self.edges.get(&id)
}
pub fn find<F>(&self, start: usize, predicate: F) -> Option<usize>
where
F: Fn(&T) -> bool,
{
let mut visited = HashSet::new();
let mut stack = vec![start];
while let Some(node_id) = stack.pop() {
if visited.contains(&node_id) {
continue;
}
visited.insert(node_id);
if let Some(value) = self.nodes.get(&node_id) {
if predicate(value) {
return Some(node_id);
}
if let Some(neighbors) = self.edges.get(&node_id) {
for &neighbor in neighbors.iter().rev() {
if !visited.contains(&neighbor) {
stack.push(neighbor);
}
}
}
}
}
None
}
pub fn node_count(&self) -> usize {
self.nodes.len()
}
}
impl<T> Default for SimpleGraph<T> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add_nodes() {
let mut graph = SimpleGraph::new();
let id1 = graph.add_node("A");
let id2 = graph.add_node("B");
assert_eq!(graph.node_count(), 2);
assert_eq!(graph.get_node(id1), Some(&"A"));
assert_eq!(graph.get_node(id2), Some(&"B"));
}
#[test]
fn test_add_edges() {
let mut graph = SimpleGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
assert!(graph.add_edge(a, b));
assert_eq!(graph.neighbors(a), Some(&vec![b]));
}
#[test]
fn test_find() {
let mut graph = SimpleGraph::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
let c = graph.add_node("C");
graph.add_edge(a, b);
graph.add_edge(b, c);
let result = graph.find(a, |&v| v == "C");
assert_eq!(result, Some(c));
}
}