From ba06a3a0dec8b132f3ad81c62f7ec98f95430f11 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Sun, 18 Sep 2016 20:31:20 +0000 Subject: [PATCH] lib: Add edge removal to graph data structure Ability to remove directed edge between two nodes. Also ensures that adjacency vectors have no null entries. Signed-off-by: Quentin Young --- lib/graph.c | 51 ++++++++++++++++++++++++++++++++++++--------------- lib/graph.h | 11 ++++++++++- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/lib/graph.c b/lib/graph.c index 18f32b8ca2..7c59fe95b5 100644 --- a/lib/graph.c +++ b/lib/graph.c @@ -50,6 +50,16 @@ graph_new_node (struct graph *graph, void *data, void (*del) (void*)) return node; } +static void +vector_remove (vector v, unsigned int ix) +{ + vector_unset (v, ix); + if (ix == vector_active (v)) return; + for (; ix < vector_active (v) - 1; ix++) + v->index[ix] = v->index[ix+1]; + v->active--; +} + void graph_delete_node (struct graph *graph, struct graph_node *node) { @@ -58,25 +68,23 @@ graph_delete_node (struct graph *graph, struct graph_node *node) // an adjacent node struct graph_node *adj; - // for all nodes that have an edge to us, remove us from their ->to - for (unsigned int i = 0; i < vector_active (node->from); i++) + // remove all edges from other nodes to us + vector edges = vector_copy (node->from); + for (unsigned int i = 0; i < vector_active (edges); i++) { - adj = vector_slot (node->from, i); - if (!adj) continue; - for (unsigned int j = 0; j < vector_active (adj->to); j++) - if (vector_slot (adj->to, j) == node) - vector_unset (adj->to, j); + adj = vector_slot (edges, i); + graph_remove_edge (adj, node); } + vector_free (edges); - // for all nodes that we have an edge to, remove us from their ->from - for (unsigned int i = 0; i < vector_active (node->to); i++) + // remove all edges from us to other nodes + edges = vector_copy (node->to); + for (unsigned int i = 0; i < vector_active (edges); i++) { - adj = vector_slot (node->to, i); - if (!adj) continue; - for (unsigned int j = 0; j < vector_active (adj->from); j++) - if (vector_slot (adj->from, j) == node) - vector_unset (adj->from, j); + adj = vector_slot (edges, i); + graph_remove_edge (node, adj); } + vector_free (edges); // if there is a deletion callback, call it if (node->del && node->data) @@ -89,7 +97,7 @@ graph_delete_node (struct graph *graph, struct graph_node *node) // remove node from graph->nodes for (unsigned int i = 0; i < vector_active (graph->nodes); i++) if (vector_slot (graph->nodes, i) == node) - vector_unset (graph->nodes, i); + vector_remove (graph->nodes, i); // free the node itself XFREE (MTYPE_GRAPH_NODE, node); @@ -103,6 +111,19 @@ graph_add_edge (struct graph_node *from, struct graph_node *to) return to; } +void +graph_remove_edge (struct graph_node *from, struct graph_node *to) +{ + // remove from from to->from + for (unsigned int i = 0; i < vector_active (to->from); i++) + if (vector_slot (to->from, i) == from) + vector_remove (to->from, i); + // remove to from from->to + for (unsigned int i = 0; i < vector_active (from->to); i++) + if (vector_slot (from->to, i) == to) + vector_remove (from->to, i); +} + void graph_delete_graph (struct graph *graph) { diff --git a/lib/graph.h b/lib/graph.h index b6a03b938a..8d8aa3823b 100644 --- a/lib/graph.h +++ b/lib/graph.h @@ -64,6 +64,7 @@ graph_new_node (struct graph *graph, void *data, void (*del) (void*)); * If *data and *del are non-null, the following call is made: * (*node->del) (node->data); * + * @param[in] graph the graph this node belongs to * @param[out] node pointer to node to delete */ void @@ -80,8 +81,16 @@ struct graph_node * graph_add_edge (struct graph_node *from, struct graph_node *to); /** - * Deletes a graph. + * Removes a directed edge between two nodes. * + * @param[in] from + * @param[in] to + */ +void +graph_remove_edge (struct graph_node *from, struct graph_node *to); + +/** + * Deletes a graph. * Calls graph_delete_node on each node before freeing the graph struct itself. * * @param graph the graph to delete