diff --git a/alib2data/src/graph/directed/AdjacencyListDirectedGraph.cpp b/alib2data/src/graph/directed/AdjacencyListDirectedGraph.cpp index 5a24566b08debe9078100c275886860b2037a677..1e308ded42627bbe97c2a8abddd0e6308b0c8a81 100644 --- a/alib2data/src/graph/directed/AdjacencyListDirectedGraph.cpp +++ b/alib2data/src/graph/directed/AdjacencyListDirectedGraph.cpp @@ -114,10 +114,10 @@ bool AdjacencyListDirectedGraph::removeEdge(const DirectedEdge &edge) edges.erase(search); - // Don't touch adj if there still is an edge, in case of multigraph - if (!findEdges(edge.getFromNode(), edge.getToNode()).empty()) { - auto &lst = adj[edge.getFromNode()]; - lst.erase(std::find(lst.begin(), lst.end(), edge.getToNode())); + auto &lst = adj[edge.getFromNode()]; + lst.erase(std::find(lst.begin(), lst.end(), edge.getToNode())); + if (lst.empty()) { + adj.erase(edge.getFromNode()); } return true; diff --git a/alib2data/src/graph/undirected/AdjacencyListUndirectedGraph.cpp b/alib2data/src/graph/undirected/AdjacencyListUndirectedGraph.cpp index f8ab017487ad67ac9ec718532605c53274709a87..6420331045059190c6f5198621da1889874c8e38 100644 --- a/alib2data/src/graph/undirected/AdjacencyListUndirectedGraph.cpp +++ b/alib2data/src/graph/undirected/AdjacencyListUndirectedGraph.cpp @@ -137,13 +137,16 @@ bool AdjacencyListUndirectedGraph::removeEdge(const UndirectedEdge &edge) edges.erase(search); - // Don't touch adj if there still is an edge, in case of multigraph - if (!findEdges(edge.getFirstNode(), edge.getSecondNode()).empty()) { - auto &lst1 = adj[edge.getFirstNode()]; - lst1.erase(std::find(lst1.begin(), lst1.end(), edge.getSecondNode())); + auto &lst1 = adj[edge.getFirstNode()]; + lst1.erase(std::find(lst1.begin(), lst1.end(), edge.getSecondNode())); + if (lst1.empty()) { + adj.erase(edge.getFirstNode()); + } - auto &lst2 = adj[edge.getSecondNode()]; - lst2.erase(std::find(lst2.begin(), lst2.end(), edge.getFirstNode())); + auto &lst2 = adj[edge.getSecondNode()]; + lst2.erase(std::find(lst2.begin(), lst2.end(), edge.getFirstNode())); + if (lst2.empty()) { + adj.erase(edge.getSecondNode()); } return true; diff --git a/alib2data/test-src/graph/GraphTest.cpp b/alib2data/test-src/graph/GraphTest.cpp index b0eb3c1f8b364411856971a2d7a2b4241ca04315..36a3359947f2a4908d07701b98468522996bc50d 100644 --- a/alib2data/test-src/graph/GraphTest.cpp +++ b/alib2data/test-src/graph/GraphTest.cpp @@ -173,3 +173,183 @@ void GraphTest::testStringParser() CPPUNIT_ASSERT(ug1 == ug2); } +void GraphTest::testAddEdge() +{ + // Common + graph::Node n1("n1"); + graph::Node n2("n2"); + graph::Node n3("n3"); + graph::Node n4("n4"); + + // Directed + graph::DirectedGraph dg(graph::REPRESENTATION::ADJACENCY_LIST); + dg.addNode(n1); + dg.addNode(n2); + dg.addNode(n3); + dg.addNode(n4); + + CPPUNIT_ASSERT(dg.getEdges().empty()); + CPPUNIT_ASSERT(dg.findEdges(n1, n2).empty()); + + dg.addEdge(graph::DirectedEdge(n1, n2)); + CPPUNIT_ASSERT(dg.getEdges().size() == 1); + CPPUNIT_ASSERT(dg.findEdges(n1, n2).size() == 1); + CPPUNIT_ASSERT(dg.findEdges(n2, n1).empty()); + + // Multi-edge can only be added with non-empty label + CPPUNIT_ASSERT(dg.addEdge(graph::DirectedEdge(n1, n2)) == false); + CPPUNIT_ASSERT(dg.getEdges().size() == 1); + CPPUNIT_ASSERT(dg.findEdges(n1, n2).size() == 1); + CPPUNIT_ASSERT(dg.findEdges(n2, n1).empty()); + + dg.addEdge(graph::DirectedEdge(n2, n3)); + CPPUNIT_ASSERT(dg.getEdges().size() == 2); + CPPUNIT_ASSERT(dg.findEdges(n2, n3).size() == 1); + CPPUNIT_ASSERT(dg.findEdges(n3, n2).empty()); + + dg.addEdge(graph::DirectedEdge(n3, n4)); + CPPUNIT_ASSERT(dg.getEdges().size() == 3); + CPPUNIT_ASSERT(dg.findEdges(n3, n4).size() == 1); + CPPUNIT_ASSERT(dg.findEdges(n4, n3).empty()); + + // Multi-edge can only be added with non-empty label + CPPUNIT_ASSERT(dg.addEdge(graph::DirectedEdge(n3, n4)) == false); + CPPUNIT_ASSERT(dg.getEdges().size() == 3); + CPPUNIT_ASSERT(dg.findEdges(n3, n4).size() == 1); + CPPUNIT_ASSERT(dg.findEdges(n4, n3).empty()); + + dg.addEdge(graph::DirectedEdge(n3, n4, "multi-edge")); + CPPUNIT_ASSERT(dg.getEdges().size() == 4); + CPPUNIT_ASSERT(dg.findEdges(n3, n4).size() == 2); + CPPUNIT_ASSERT(dg.findEdges(n4, n3).empty()); + + // Undirected + graph::UndirectedGraph ug(graph::REPRESENTATION::ADJACENCY_LIST); + ug.addNode(n1); + ug.addNode(n2); + ug.addNode(n3); + ug.addNode(n4); + + CPPUNIT_ASSERT(ug.getEdges().empty()); + CPPUNIT_ASSERT(ug.findEdges(n1, n2).empty()); + + ug.addEdge(graph::UndirectedEdge(n1, n2)); + CPPUNIT_ASSERT(ug.getEdges().size() == 1); + CPPUNIT_ASSERT(ug.findEdges(n1, n2).size() == 1); + CPPUNIT_ASSERT(ug.findEdges(n2, n1).size() == 1); + + // Multi-edge can only be added with non-empty label + CPPUNIT_ASSERT(ug.addEdge(graph::UndirectedEdge(n1, n2)) == false); + CPPUNIT_ASSERT(ug.getEdges().size() == 1); + CPPUNIT_ASSERT(ug.findEdges(n1, n2).size() == 1); + CPPUNIT_ASSERT(ug.findEdges(n2, n1).size() == 1); + + ug.addEdge(graph::UndirectedEdge(n2, n3)); + CPPUNIT_ASSERT(ug.getEdges().size() == 2); + CPPUNIT_ASSERT(ug.findEdges(n2, n3).size() == 1); + CPPUNIT_ASSERT(ug.findEdges(n3, n2).size() == 1); + + ug.addEdge(graph::UndirectedEdge(n3, n4)); + CPPUNIT_ASSERT(ug.getEdges().size() == 3); + CPPUNIT_ASSERT(ug.findEdges(n3, n4).size() == 1); + CPPUNIT_ASSERT(ug.findEdges(n4, n3).size() == 1); + + // Multi-edge can only be added with non-empty label + CPPUNIT_ASSERT(ug.addEdge(graph::UndirectedEdge(n3, n4)) == false); + CPPUNIT_ASSERT(ug.getEdges().size() == 3); + CPPUNIT_ASSERT(ug.findEdges(n3, n4).size() == 1); + CPPUNIT_ASSERT(ug.findEdges(n4, n3).size() == 1); + + ug.addEdge(graph::UndirectedEdge(n3, n4, "multi-edge")); + CPPUNIT_ASSERT(ug.getEdges().size() == 4); + CPPUNIT_ASSERT(ug.findEdges(n3, n4).size() == 2); + CPPUNIT_ASSERT(ug.findEdges(n4, n3).size() == 2); +} + +void GraphTest::testRemoveEdge() +{ + // Common + graph::Node n1("n1"); + graph::Node n2("n2"); + graph::Node n3("n3"); + graph::Node n4("n4"); + + // Directed + graph::DirectedGraph dg(graph::REPRESENTATION::ADJACENCY_LIST); + dg.addEdge(graph::DirectedEdge(n1, n2)); + dg.addEdge(graph::DirectedEdge(n1, n2, "multi-edge")); + dg.addEdge(graph::DirectedEdge(n2, n3)); + dg.addEdge(graph::DirectedEdge(n3, n4)); + dg.addEdge(graph::DirectedEdge(n4, n1)); + + CPPUNIT_ASSERT(dg.getNodes().size() == 4); + CPPUNIT_ASSERT(dg.getEdges().size() == 5); + + CPPUNIT_ASSERT(dg.neighbors(n1).size() == 1); + dg.removeEdge(graph::DirectedEdge(n1, n2)); + CPPUNIT_ASSERT(dg.findEdges(n1, n2).size() == 1); + CPPUNIT_ASSERT(dg.neighbors(n1).size() == 1); + + CPPUNIT_ASSERT(dg.neighbors(n1).size() == 1); + dg.removeEdge(graph::DirectedEdge(n1, n2, "multi-edge")); + CPPUNIT_ASSERT(dg.findEdges(n1, n2).size() == 0); + CPPUNIT_ASSERT(dg.neighbors(n1).empty()); + + CPPUNIT_ASSERT(dg.neighbors(n2).size() == 1); + dg.removeEdge(graph::DirectedEdge(n2, n3)); + CPPUNIT_ASSERT(dg.findEdges(n2, n3).size() == 0); + CPPUNIT_ASSERT(dg.neighbors(n2).empty()); + + CPPUNIT_ASSERT(dg.neighbors(n3).size() == 1); + dg.removeEdge(graph::DirectedEdge(n3, n4)); + CPPUNIT_ASSERT(dg.findEdges(n3, n4).size() == 0); + CPPUNIT_ASSERT(dg.neighbors(n3).empty()); + + CPPUNIT_ASSERT(dg.neighbors(n4).size() == 1); + dg.removeEdge(graph::DirectedEdge(n4, n1)); + CPPUNIT_ASSERT(dg.findEdges(n4, n1).size() == 0); + CPPUNIT_ASSERT(dg.neighbors(n4).empty()); + + CPPUNIT_ASSERT(dg.getEdges().empty()); + CPPUNIT_ASSERT(dg.getNodes().empty()); + + // Undirected + graph::UndirectedGraph ug(graph::REPRESENTATION::ADJACENCY_LIST); + ug.addEdge(graph::UndirectedEdge(n1, n2)); + ug.addEdge(graph::UndirectedEdge(n1, n2, "multi-edge")); + ug.addEdge(graph::UndirectedEdge(n2, n3)); + ug.addEdge(graph::UndirectedEdge(n3, n4)); + ug.addEdge(graph::UndirectedEdge(n4, n1)); + + CPPUNIT_ASSERT(ug.getNodes().size() == 4); + CPPUNIT_ASSERT(ug.getEdges().size() == 5); + + CPPUNIT_ASSERT(ug.neighbors(n1).size() == 2); + ug.removeEdge(graph::UndirectedEdge(n1, n2)); + CPPUNIT_ASSERT(ug.findEdges(n1, n2).size() == 1); + CPPUNIT_ASSERT(ug.neighbors(n1).size() == 2); + + CPPUNIT_ASSERT(ug.neighbors(n1).size() == 2); + ug.removeEdge(graph::UndirectedEdge(n1, n2, "multi-edge")); + CPPUNIT_ASSERT(ug.findEdges(n1, n2).size() == 0); + CPPUNIT_ASSERT(ug.neighbors(n1).size() == 1); + + CPPUNIT_ASSERT(ug.neighbors(n2).size() == 1); + ug.removeEdge(graph::UndirectedEdge(n2, n3)); + CPPUNIT_ASSERT(ug.findEdges(n2, n3).size() == 0); + CPPUNIT_ASSERT(ug.neighbors(n2).empty()); + + CPPUNIT_ASSERT(ug.neighbors(n3).size() == 1); + ug.removeEdge(graph::UndirectedEdge(n3, n4)); + CPPUNIT_ASSERT(ug.findEdges(n3, n4).size() == 0); + CPPUNIT_ASSERT(ug.neighbors(n3).empty()); + + CPPUNIT_ASSERT(ug.neighbors(n4).size() == 1); + ug.removeEdge(graph::UndirectedEdge(n4, n1)); + CPPUNIT_ASSERT(ug.findEdges(n4, n1).size() == 0); + CPPUNIT_ASSERT(ug.neighbors(n4).empty()); + + CPPUNIT_ASSERT(ug.getEdges().empty()); + CPPUNIT_ASSERT(ug.getNodes().empty()); +} + diff --git a/alib2data/test-src/graph/GraphTest.h b/alib2data/test-src/graph/GraphTest.h index 522756916996bb5f4bda00edaee7c573f077ea39..c2f4147fc58eac3a71abfd5831a4601e4ec9057e 100644 --- a/alib2data/test-src/graph/GraphTest.h +++ b/alib2data/test-src/graph/GraphTest.h @@ -10,6 +10,8 @@ class GraphTest : public CppUnit::TestFixture CPPUNIT_TEST(testEqual); CPPUNIT_TEST(testXMLParser); CPPUNIT_TEST(testStringParser); + CPPUNIT_TEST(testAddEdge); + CPPUNIT_TEST(testRemoveEdge); CPPUNIT_TEST_SUITE_END(); public: @@ -20,6 +22,9 @@ public: void testEqual(); void testXMLParser(); void testStringParser(); + + void testAddEdge(); + void testRemoveEdge(); }; #endif // GRAPH_TEST_H_