Created
February 17, 2023 18:04
-
-
Save matthewjberger/80c13528d5fc38dcf6b7c5c3aeabd9bf to your computer and use it in GitHub Desktop.
Adjacency list in rust (from: https://github.com/EbTech/rust-algorithms/blob/master/src/graph/mod.rs)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// A compact graph representation. Edges are numbered in order of insertion. | |
/// Each adjacency list consists of all edges pointing out from a given vertex. | |
pub struct Graph { | |
/// Maps a vertex id to the first edge in its adjacency list. | |
first: Vec<Option<usize>>, | |
/// Maps an edge id to the next edge in the same adjacency list. | |
next: Vec<Option<usize>>, | |
/// Maps an edge id to the vertex that it points to. | |
endp: Vec<usize>, | |
} | |
impl Graph { | |
/// Initializes a graph with vmax vertices and no edges. To reduce | |
/// unnecessary allocations, emax_hint should be close to the number of | |
/// edges that will be inserted. | |
pub fn new(vmax: usize, emax_hint: usize) -> Self { | |
Self { | |
first: vec![None; vmax], | |
next: Vec::with_capacity(emax_hint), | |
endp: Vec::with_capacity(emax_hint), | |
} | |
} | |
/// Returns the number of vertices. | |
pub fn num_v(&self) -> usize { | |
self.first.len() | |
} | |
/// Returns the number of edges, double-counting undirected edges. | |
pub fn num_e(&self) -> usize { | |
self.endp.len() | |
} | |
/// Adds a directed edge from u to v. | |
pub fn add_edge(&mut self, u: usize, v: usize) { | |
self.next.push(self.first[u]); | |
self.first[u] = Some(self.num_e()); | |
self.endp.push(v); | |
} | |
/// An undirected edge is two directed edges. If edges are added only via | |
/// this funcion, the reverse of any edge e can be found at e^1. | |
pub fn add_undirected_edge(&mut self, u: usize, v: usize) { | |
self.add_edge(u, v); | |
self.add_edge(v, u); | |
} | |
/// If we think of each even-numbered vertex as a variable, and its | |
/// odd-numbered successor as its negation, then we can build the | |
/// implication graph corresponding to any 2-CNF formula. | |
/// Note that u||v == !u -> v == !v -> u. | |
pub fn add_two_sat_clause(&mut self, u: usize, v: usize) { | |
self.add_edge(u ^ 1, v); | |
self.add_edge(v ^ 1, u); | |
} | |
/// Gets vertex u's adjacency list. | |
pub fn adj_list(&self, u: usize) -> AdjListIterator { | |
AdjListIterator { | |
graph: self, | |
next_e: self.first[u], | |
} | |
} | |
} | |
/// An iterator for convenient adjacency list traversal. | |
pub struct AdjListIterator<'a> { | |
graph: &'a Graph, | |
next_e: Option<usize>, | |
} | |
impl<'a> Iterator for AdjListIterator<'a> { | |
type Item = (usize, usize); | |
/// Produces an outgoing edge and vertex. | |
fn next(&mut self) -> Option<Self::Item> { | |
self.next_e.map(|e| { | |
let v = self.graph.endp[e]; | |
self.next_e = self.graph.next[e]; | |
(e, v) | |
}) | |
} | |
} | |
#[cfg(test)] | |
mod test { | |
use super::*; | |
#[test] | |
fn test_adj_list() { | |
let mut graph = Graph::new(5, 6); | |
graph.add_edge(2, 3); | |
graph.add_edge(2, 4); | |
graph.add_edge(4, 1); | |
graph.add_edge(1, 2); | |
graph.add_undirected_edge(0, 2); | |
let adj = graph.adj_list(2).collect::<Vec<_>>(); | |
assert_eq!(adj, vec![(5, 0), (1, 4), (0, 3)]); | |
for (e, v) in adj { | |
assert_eq!(v, graph.endp[e]); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment