Skip to content

Commit 1bf66aa

Browse files
committed
Added tips iterator
1 parent f011acb commit 1bf66aa

1 file changed

Lines changed: 97 additions & 29 deletions

File tree

src/graph.rs

Lines changed: 97 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ pub enum GraphErr {
3333
pub struct Graph<T> {
3434
vertices: HashMap<VertexId, (T, VertexId)>,
3535
edges: HashMap<Edge, f32>,
36-
roots: Vec<VertexId>,
36+
roots: HashSet<VertexId>,
37+
tips: HashSet<VertexId>,
3738
inbound_table: HashMap<VertexId, Vec<VertexId>>,
3839
outbound_table: HashMap<VertexId, Vec<VertexId>>,
3940
}
@@ -54,7 +55,8 @@ impl<T> Graph<T> {
5455
Graph {
5556
vertices: HashMap::new(),
5657
edges: HashMap::new(),
57-
roots: Vec::new(),
58+
roots: HashSet::new(),
59+
tips: HashSet::new(),
5860
inbound_table: HashMap::new(),
5961
outbound_table: HashMap::new(),
6062
}
@@ -69,10 +71,17 @@ impl<T> Graph<T> {
6971
/// let mut graph: Graph<usize> = Graph::with_capacity(5);
7072
/// ```
7173
pub fn with_capacity(capacity: usize) -> Graph<T> {
74+
let edges_capacity = if capacity < 100 {
75+
usize::pow(capacity, 2)
76+
} else {
77+
capacity
78+
};
79+
7280
Graph {
7381
vertices: HashMap::with_capacity(capacity),
74-
edges: HashMap::with_capacity(usize::pow(capacity, 2)),
75-
roots: Vec::with_capacity(capacity),
82+
edges: HashMap::with_capacity(edges_capacity),
83+
roots: HashSet::with_capacity(capacity),
84+
tips: HashSet::with_capacity(capacity),
7685
inbound_table: HashMap::with_capacity(capacity),
7786
outbound_table: HashMap::with_capacity(capacity),
7887
}
@@ -85,13 +94,14 @@ impl<T> Graph<T> {
8594
///
8695
/// let mut graph: Graph<usize> = Graph::with_capacity(5);
8796
///
88-
/// assert_eq!(graph.capacity(), 5);
97+
/// assert!(graph.capacity() >= 5);
8998
/// ```
9099
pub fn capacity(&self) -> usize {
91100
min!(
92101
self.vertices.capacity(),
93102
self.edges.capacity(),
94103
self.roots.capacity(),
104+
self.tips.capacity(),
95105
self.inbound_table.capacity(),
96106
self.outbound_table.capacity()
97107
)
@@ -121,12 +131,17 @@ impl<T> Graph<T> {
121131
// number of vertices that are currently placed
122132
// in the graph.
123133
let new_capacity = self.vertices.len() + additional;
124-
let edges_capacity = usize::pow(new_capacity, 2);
134+
let edges_capacity = if new_capacity < 100 {
135+
usize::pow(new_capacity, 2)
136+
} else {
137+
new_capacity
138+
};
125139
let edges_count = self.edges.len();
126140
let edges_additional = edges_capacity - edges_count;
127141

128142
self.edges.reserve(edges_additional);
129143
self.roots.reserve(additional);
144+
self.tips.reserve(additional);
130145
self.vertices.reserve(additional);
131146
self.outbound_table.reserve(additional);
132147
self.inbound_table.reserve(additional);
@@ -142,14 +157,15 @@ impl<T> Graph<T> {
142157
///
143158
/// let mut graph: Graph<usize> = Graph::with_capacity(5);
144159
///
145-
/// assert_eq!(graph.capacity(), 5);
160+
/// assert!(graph.capacity() >= 5);
146161
///
147162
/// graph.shrink_to_fit();
148-
/// assert_eq!(graph.capacity(), 0);
163+
/// assert!(graph.capacity() < 5);
149164
/// ```
150165
pub fn shrink_to_fit(&mut self) {
151166
self.edges.shrink_to_fit();
152167
self.roots.shrink_to_fit();
168+
self.tips.shrink_to_fit();
153169
self.vertices.shrink_to_fit();
154170
self.outbound_table.shrink_to_fit();
155171
self.inbound_table.shrink_to_fit();
@@ -181,7 +197,8 @@ impl<T> Graph<T> {
181197
let id = VertexId::random();
182198

183199
self.vertices.insert(id.clone(), (item, id.clone()));
184-
self.roots.push(id);
200+
self.roots.insert(id);
201+
self.tips.insert(id);
185202

186203
id
187204
}
@@ -468,18 +485,35 @@ impl<T> Graph<T> {
468485
/// ```
469486
pub fn remove(&mut self, id: &VertexId) {
470487
self.vertices.remove(id);
471-
self.inbound_table.remove(id);
472488

473-
// Mark outbounds as roots if they have no inbounds.
474-
for (n, _) in self.outbound_table.iter() {
475-
if self.in_neighbors_count(n) == 0 {
476-
self.roots.push(n.clone());
489+
// Remove each inbound edge
490+
if let Some(inbounds) = self.inbound_table.remove(id) {
491+
for vertex in inbounds {
492+
self.remove_edge(&vertex, id);
493+
494+
// Add to tips if inbound vertex doesn't
495+
// have other outbound vertices.
496+
if self.out_neighbors_count(&vertex) == 0 {
497+
self.tips.insert(vertex);
498+
}
499+
}
500+
}
501+
502+
// Remove each outbound edge
503+
if let Some(outbounds) = self.outbound_table.remove(id) {
504+
for vertex in outbounds {
505+
self.remove_edge(id, &vertex);
506+
507+
// Add to roots if outbound vertex doesn't
508+
// have other inbound vertices.
509+
if self.in_neighbors_count(&vertex) == 0 {
510+
self.roots.insert(vertex);
511+
}
477512
}
478513
}
479514

480-
self.outbound_table.remove(id);
481-
self.edges.retain(|e, _| !e.matches_any(id));
482-
self.roots.retain(|r| r != id);
515+
self.roots.remove(&id);
516+
self.tips.remove(&id);
483517
}
484518

485519
/// Removes the specified edge from the graph.
@@ -509,22 +543,22 @@ impl<T> Graph<T> {
509543
/// assert_eq!(graph.edge_count(), 2);
510544
/// ```
511545
pub fn remove_edge(&mut self, a: &VertexId, b: &VertexId) {
512-
let mut remove = false;
513-
514546
if let Some(outbounds) = self.outbound_table.get_mut(a) {
515547
outbounds.retain(|v| v != b);
516-
remove = true;
517548
}
518549

519550
// If outbound vertex doesn't have any more inbounds,
520551
// mark it as root.
521552
if self.in_neighbors_count(&b) == 0 {
522-
self.roots.push(b.clone());
553+
self.roots.insert(b.clone());
523554
}
524555

525-
if remove {
526-
self.edges.retain(|e, _| !e.matches(a, b));
556+
// Mark vertex as tip if it doesn't have any more outbounds.
557+
if self.out_neighbors_count(&a) == 0 {
558+
self.tips.insert(a.clone());
527559
}
560+
561+
self.edges.remove(&Edge::new(a.clone(), b.clone()));
528562
}
529563

530564
/// Iterates through the graph and only keeps
@@ -547,14 +581,12 @@ impl<T> Graph<T> {
547581
/// assert_eq!(graph.vertex_count(), 2);
548582
/// ```
549583
pub fn retain(&mut self, fun: impl Fn(&T) -> bool) {
550-
let vertices: Vec<VertexId> = self.vertices().cloned().collect();
551-
let vertices: Vec<VertexId> = vertices
552-
.iter()
584+
let vertices: Vec<VertexId> = self.vertices()
553585
.filter(|v| !fun(self.fetch(v).unwrap()))
554586
.cloned()
555587
.collect();
556-
557-
vertices.iter().for_each(|v| self.remove(v));
588+
589+
vertices.iter().for_each(|v| self.remove(&v));
558590
}
559591

560592
/// Performs a fold over the vertices that are
@@ -879,6 +911,39 @@ impl<T> Graph<T> {
879911
VertexIter(Box::new(self.roots.iter().map(AsRef::as_ref)))
880912
}
881913

914+
/// Returns an iterator over the tips of the graph. These
915+
/// are all the vertices that have an inbound edge but no
916+
/// outbound edge.
917+
///
918+
/// ## Example
919+
/// ```rust
920+
/// use graphlib::Graph;
921+
///
922+
/// let mut graph: Graph<usize> = Graph::new();
923+
/// let mut tips = vec![];
924+
///
925+
/// let v1 = graph.add_vertex(0);
926+
/// let v2 = graph.add_vertex(1);
927+
/// let v3 = graph.add_vertex(2);
928+
/// let v4 = graph.add_vertex(3);
929+
///
930+
/// graph.add_edge(&v1, &v2).unwrap();
931+
/// graph.add_edge(&v3, &v1).unwrap();
932+
/// graph.add_edge(&v1, &v4).unwrap();
933+
///
934+
/// // Iterate over tips
935+
/// for v in graph.tips() {
936+
/// tips.push(v);
937+
/// }
938+
///
939+
/// assert_eq!(tips.len(), 2);
940+
/// assert_eq!(tips[0], &v2);
941+
/// assert_eq!(tips[1], &v4);
942+
/// ```
943+
pub fn tips(&self) -> VertexIter<'_> {
944+
VertexIter(Box::new(self.tips.iter().map(AsRef::as_ref)))
945+
}
946+
882947
/// Returns an iterator over all of the
883948
/// vertices that are placed in the graph.
884949
///
@@ -1059,7 +1124,10 @@ impl<T> Graph<T> {
10591124
}
10601125

10611126
// Remove outbound vertex from roots
1062-
self.roots = self.roots.iter().filter(|v| *v != b).cloned().collect();
1127+
self.roots.remove(&b);
1128+
1129+
// Remove inbound vertex from tips
1130+
self.tips.remove(&a);
10631131

10641132
Ok(())
10651133
}

0 commit comments

Comments
 (0)