Add Graph::delete_vertex() implementation

This commit is contained in:
2026-04-29 20:50:19 +02:00
parent b3dc0ea666
commit 09c5850ff3
+47 -14
View File
@@ -56,6 +56,19 @@ impl<'a> Iterator for VertexIncidenceIterator<'a> {
}
}
struct VertexIncidenceCursor {
incidence: Option<IncidenceSlot>,
}
impl VertexIncidenceCursor {
fn next(&mut self, graph: &Graph) -> Option<Edge> {
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<VertexIncidenceHeader, usize, usize>,
@@ -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);