After reading the rust book for some time I decided to create my first program which implements a graph.
There are a few things I was wondering about, such as if the file structure is appropriate (the graph.rs just containing a few mod statements feels weird).
Also to store pointers to the edges I had to use Rc and I am not sure if that is the correct choice?
And finally I'm also wondering if there is a more idiomatic rust way to write certain code ?
Other comments are welcome as well of course.
main.rs:
use crate::graph::edge::Edge;
use crate::graph::graph::Graph;
use crate::graph::node::Node;
use std::collections::HashMap;
use std::rc::Rc;
pub mod graph;
fn main() {
let g = create_graph();
println!("graph connected: {}", g.is_fully_connected());
}
fn create_graph() -> Graph {
let n: Vec<Node> = vec![Node::new(), Node::new(), Node::new()];
let edge1 = &Rc::new(Edge::new(0, 1));
let edge2 = &Rc::new(Edge::new(0, 2));
let edge3 = &Rc::new(Edge::new(1, 2));
let mut neighbors = HashMap::new();
let neighbors0 = vec![Rc::clone(edge1), Rc::clone(edge2)];
let neighbors1 = vec![Rc::clone(edge1), Rc::clone(edge3)];
let neighbors2 = vec![Rc::clone(edge2), Rc::clone(edge3)];
neighbors.insert(0, neighbors0);
neighbors.insert(1, neighbors1);
neighbors.insert(2, neighbors2);
Graph::new(n, neighbors)
}
graph.rs:
pub mod graph;
pub mod edge;
pub mod node;
graph/node.rs:
pub struct Node {
//TODO coordinates
}
impl Node {
#[inline]
pub fn new() -> Self {
Node {}
}
}
graph/edge.rs
pub struct Edge {
pub node_a: i32,
pub node_b: i32,
}
impl Edge {
#[inline]
pub fn new(node_a: i32, node_b: i32) -> Self {
Edge {
node_a: node_a,
node_b: node_b,
}
}
//if base_node is neither of the edge nodes then the result is considered random
pub fn get_adj_node(&self, base_node: i32) -> i32 {
if base_node == self.node_a {
self.node_b
} else {
self.node_a
}
}
}
graph/graph.rs:
use super::edge::Edge;
use super::node::Node;
use std::collections::HashMap;
use std::collections::HashSet;
use std::rc::Rc;
pub struct Graph {
nodes: Vec<Node>,
neighbors: HashMap<i32, Vec<Rc<Edge>>>, //node index to coinciding edges
}
impl Graph {
pub fn new(nodes: Vec<Node>, neighbors: HashMap<i32, Vec<Rc<Edge>>>) -> Self {
Graph {
nodes: nodes,
neighbors: neighbors,
}
}
pub fn is_fully_connected(&self) -> bool {
let mut index = 0;
let mut stack = vec![index];
let mut used = HashSet::from([index]);
while !stack.is_empty() {
index = stack.pop().unwrap();
let neighbors = match self.neighbors.get(&index) {
None => continue,
Some(n) => n,
};
for edge in neighbors {
let adj_node = edge.get_adj_node(index);
if !used.contains(&adj_node) {
used.insert(adj_node);
stack.push(adj_node);
}
}
}
used.len() == self.nodes.len()
}
}