Skip to content

Commit 5fc8449

Browse files
authored
Fix bug in Eulerian path algorithm (#314)
* Fix choice of starting node in eulerian path algorithm * Add test of eulerian path for undirected graph * Rewrite choice of next node in eulerian path algorithm
1 parent d218e13 commit 5fc8449

File tree

4 files changed

+66
-5
lines changed

4 files changed

+66
-5
lines changed

include/Edge/Edge.hpp

100755100644
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class Edge {
4646
virtual ~Edge() = default;
4747
const unsigned long long &getId() const;
4848
const std::pair<const Node<T> *, const Node<T> *> &getNodePair() const;
49+
const Node<T> *getOtherNode(const Node<T> *node) const;
4950
virtual const std::optional<bool> isDirected() const;
5051
virtual const std::optional<bool> isWeighted() const;
5152
// operator
@@ -83,6 +84,15 @@ const std::pair<const Node<T> *, const Node<T> *> &Edge<T>::getNodePair()
8384
return nodePair;
8485
}
8586

87+
template <typename T>
88+
const Node<T> *Edge<T>::getOtherNode(const Node<T> *node) const {
89+
if (this->getNodePair().first == node) {
90+
return this->getNodePair().second;
91+
} else {
92+
return this->getNodePair().first;
93+
}
94+
}
95+
8696
template <typename T>
8797
const std::optional<bool> Edge<T>::isDirected() const {
8898
return std::nullopt;
@@ -112,4 +122,4 @@ std::ostream &operator<<(std::ostream &os, const Edge<T> &edge) {
112122
}
113123
} // namespace CXXGraph
114124

115-
#endif // __CXXGRAPH_EDGE_H__
125+
#endif // __CXXGRAPH_EDGE_H__

include/Edge/UndirectedEdge.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,4 @@ std::ostream &operator<<(std::ostream &os, const UndirectedEdge<T> &edge) {
9999
}
100100
} // namespace CXXGraph
101101

102-
#endif // __CXXGRAPH_UNDIRECTEDEDGE_H__
102+
#endif // __CXXGRAPH_UNDIRECTEDEDGE_H__

include/Graph/Graph.hpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,18 +1150,32 @@ template <typename T>
11501150
std::shared_ptr<std::vector<Node<T>>> Graph<T>::eulerianPath() const {
11511151
const auto nodeSet = Graph<T>::getNodeSet();
11521152
const auto adj = Graph<T>::getAdjMatrix();
1153+
11531154
std::shared_ptr<std::vector<Node<T>>> eulerPath =
11541155
std::make_shared<std::vector<Node<T>>>();
1156+
1157+
bool undirected = this->isUndirectedGraph();
1158+
11551159
std::vector<const Node<T> *> currentPath;
1156-
auto currentNode = *(nodeSet.begin());
1160+
// The starting node is the only node which has more outgoing than ingoing
1161+
// links
1162+
auto firstNodeIt =
1163+
std::max_element(nodeSet.begin(), nodeSet.end(), [adj](auto n1, auto n2) {
1164+
return adj->at(n1).size() < adj->at(n2).size();
1165+
});
1166+
auto currentNode = *(firstNodeIt);
11571167
currentPath.push_back(currentNode);
1168+
11581169
while (currentPath.size() > 0) {
11591170
auto &edges = adj->at(currentNode);
11601171
// we keep removing the edges that
11611172
// have been traversed from the adjacency list
11621173
if (edges.size()) {
11631174
auto firstEdge = edges.back().second;
1164-
auto nextNodeId = firstEdge->getNodePair().second;
1175+
1176+
const Node<T> *nextNodeId;
1177+
nextNodeId = firstEdge->getOtherNode(currentNode);
1178+
11651179
currentPath.push_back(nextNodeId);
11661180
currentNode = nextNodeId;
11671181
edges.pop_back();

test/EulerPathTest.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,41 @@ TEST(EulerPathTest, test_3) {
104104

105105
ASSERT_FALSE(check);
106106
}
107-
}
107+
}
108+
109+
TEST(EulerPathTest, test_4) {
110+
CXXGraph::Node<int> node_a("a", 0);
111+
CXXGraph::Node<int> node_b("b", 1);
112+
CXXGraph::Node<int> node_c("c", 2);
113+
CXXGraph::Node<int> node_d("d", 3);
114+
CXXGraph::Node<int> node_e("e", 4);
115+
CXXGraph::Node<int> node_f("f", 5);
116+
117+
CXXGraph::UndirectedEdge<int> edge1(1, node_a, node_b);
118+
CXXGraph::UndirectedEdge<int> edge2(2, node_b, node_e);
119+
CXXGraph::UndirectedEdge<int> edge3(3, node_e, node_f);
120+
CXXGraph::UndirectedEdge<int> edge4(4, node_f, node_a);
121+
CXXGraph::UndirectedEdge<int> edge5(5, node_b, node_c);
122+
CXXGraph::UndirectedEdge<int> edge6(6, node_b, node_d);
123+
CXXGraph::UndirectedEdge<int> edge7(7, node_c, node_d);
124+
125+
CXXGraph::T_EdgeSet<int> edgeSet;
126+
edgeSet.insert(&edge1);
127+
edgeSet.insert(&edge2);
128+
edgeSet.insert(&edge3);
129+
edgeSet.insert(&edge4);
130+
edgeSet.insert(&edge5);
131+
edgeSet.insert(&edge6);
132+
edgeSet.insert(&edge7);
133+
134+
CXXGraph::Graph<int> graph(edgeSet);
135+
auto res = graph.eulerianPath();
136+
auto nodeSet = graph.getNodeSet();
137+
for (const auto& node : nodeSet) {
138+
auto check = std::find_if(res->begin(), res->end(), [node](auto it) {
139+
return (node->getUserId() == it.getUserId());
140+
}) == res->end();
141+
142+
ASSERT_FALSE(check);
143+
}
144+
}

0 commit comments

Comments
 (0)