From 09c5850ff3e126a7d6167fa638009b113ae87cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Wed, 29 Apr 2026 20:50:19 +0200 Subject: [PATCH] Add Graph::delete_vertex() implementation --- src/models/graph.rs | 61 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/src/models/graph.rs b/src/models/graph.rs index 0d3868b..4f6e16f 100644 --- a/src/models/graph.rs +++ b/src/models/graph.rs @@ -56,6 +56,19 @@ impl<'a> Iterator for VertexIncidenceIterator<'a> { } } +struct VertexIncidenceCursor { + incidence: Option, +} + +impl VertexIncidenceCursor { + fn next(&mut self, graph: &Graph) -> Option { + let current = self.incidence?; + let index = graph.incidences.get_idx(current.0)?; + self.incidence = graph.incidences[index].next; + Some(index) + } +} + pub struct Graph { // TODO: Arena index and generation types could be externalized to Graph. vertices: Arena, @@ -82,6 +95,22 @@ impl Graph { edge } + fn remove_incidence_pair(&mut self, e: Edge) -> (Edge, IncidenceEntry, IncidenceEntry) { + let f = self + .incidences + .get_idx(e.arr_idx() ^ 1) + .expect("invalid paired incidence index, corrupt internal data state"); + let e_entry = self + .incidences + .remove(e) + .expect("attempt to delete an invalid edge"); + let f_entry = self + .incidences + .remove(f) + .expect("cannot read paired incidence, corrupt internal data state"); + (f, e_entry, f_entry) + } + // Updates the source vertex incidence list after the incidence "e" was deleted from the // incidences arena. "next" is the next incidence after "e" in the source vertex incidence list. fn update_incidence_list( @@ -169,26 +198,30 @@ impl GraphTopology for Graph { // TODO: Benchmark delete with storing "previous" in O(1) vs. linear lookup in O(degree). impl GraphTopologyDeletion for Graph { fn delete_vertex(&mut self, v: Self::Vertex) { - todo!() + let v_header = self + .vertices + .remove(v) + .expect("attempt to delete an invalid vertex"); + let mut cursor = VertexIncidenceCursor { + incidence: v_header.first_incidence, + }; + while let Some(e) = cursor.next(self) { + // Since v is being deleted, there are no update_incidence_list() calls for e, no need + // to fix v's incidence list. + let (f, e_entry, f_entry) = self.remove_incidence_pair(e); + if e_entry.neighbor != f_entry.neighbor { + self.update_incidence_list(f, e_entry.neighbor, f_entry.next, false); + } else { + cursor.incidence = f_entry.next; + } + } } // The incidence entries are removed before patching the linked lists. This is safe because // update_incidence_list() searches by raw slot index (IncidenceSlot.0) and only dereferences // the predecessor, never the removed entries themselves. fn delete_edge(&mut self, e: Self::Edge) { - let f = self - .incidences - .get_idx(e.arr_idx() ^ 1) - .expect("invalid paired incidence index, corrupt internal data state"); - let e_entry = &self - .incidences - .remove(e) - .expect("attempt to delete an invalid edge"); - let f_entry = &self - .incidences - .remove(f) - .expect("cannot read paired incidence, corrupt internal data state"); - + let (f, e_entry, f_entry) = self.remove_incidence_pair(e); if e_entry.neighbor != f_entry.neighbor { self.update_incidence_list(e, f_entry.neighbor, e_entry.next, false); self.update_incidence_list(f, e_entry.neighbor, f_entry.next, false);