Skip to content

Commit 6d44527

Browse files
authored
Merge pull request #30 from Debashis08/release
Release
2 parents 7ad9f6d + 3bacc51 commit 6d44527

File tree

5 files changed

+289
-0
lines changed

5 files changed

+289
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#pragma once
2+
3+
#include<map>
4+
#include<vector>
5+
#include<list>
6+
using namespace std;
7+
8+
namespace EulerianPathAndCircuit
9+
{
10+
class Node
11+
{
12+
public:
13+
int data;
14+
int degree;
15+
int inDegree;
16+
int outDegree;
17+
bool visited;
18+
Node(int value);
19+
};
20+
21+
class Graph
22+
{
23+
private:
24+
bool _isEulerianPathPresent;
25+
bool _isEulerianCircuitPresent;
26+
map<Node*, list<Node*>> _adjlist;
27+
map<int, Node*> _nodeMap;
28+
vector<int> _eulerianPath;
29+
Node* MakeOrFindNode(int value);
30+
void DepthFirstSearch(Node* node);
31+
bool IsConnected();
32+
void EulerianPathHierholzerAlgorithm(Node* startingNode);
33+
34+
public:
35+
void PushUndirectedEdge(int valueU, int valueV);
36+
void PushDirectedEdge(int valueU, int valueV);
37+
void PushSingleNode(int valueU);
38+
void FindEulerianPathAndCircuit();
39+
bool IsEulerianPathPresent();
40+
bool IsEulerianCircuitPresent();
41+
vector<int> UndirectedGraphGetEulerianPath();
42+
};
43+
}
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
#include "../Headers/0003_Graph/0006_EulerianPathAndCircuit.h"
2+
#include<stack>
3+
#include<algorithm>
4+
using namespace std;
5+
6+
namespace EulerianPathAndCircuit
7+
{
8+
Node::Node(int value)
9+
{
10+
this->data = value;
11+
this->degree = 0;
12+
this->inDegree = 0;
13+
this->outDegree = 0;
14+
this->visited = false;
15+
}
16+
17+
// Graph Private Member Methods
18+
Node* Graph::MakeOrFindNode(int value)
19+
{
20+
Node* node = nullptr;
21+
if (this->_nodeMap.find(value) == this->_nodeMap.end())
22+
{
23+
node = new Node(value);
24+
this->_nodeMap[value] = node;
25+
}
26+
else
27+
{
28+
node = this->_nodeMap[value];
29+
}
30+
return node;
31+
}
32+
33+
void Graph::DepthFirstSearch(Node* nodeU)
34+
{
35+
nodeU->visited = true;
36+
for (auto& nodeV : this->_adjlist[nodeU])
37+
{
38+
if (nodeV->visited == false)
39+
{
40+
this->DepthFirstSearch(nodeV);
41+
}
42+
}
43+
}
44+
45+
bool Graph::IsConnected()
46+
{
47+
// Step-1 : Make the visited property of all nodes as false. It is already done in constructor.
48+
49+
// Step-2 : Find a node which do not have 0 degree.
50+
Node* node = nullptr;
51+
for (auto& iterator : this->_nodeMap)
52+
{
53+
if (iterator.second->degree != 0)
54+
{
55+
node = iterator.second;
56+
break;
57+
}
58+
}
59+
60+
// Step-3 : If node is null, it means G.E is null, so G is connected, else call DFS to traverse the graph G.
61+
if (node == nullptr)
62+
{
63+
return true;
64+
}
65+
66+
this->DepthFirstSearch(node);
67+
68+
// Step-4 : Checking if all the non-zero degree vertices have been visited or not.
69+
for (auto& iterator : this->_nodeMap)
70+
{
71+
if (iterator.second->visited == false && iterator.second->degree != 0)
72+
{
73+
return false;
74+
}
75+
}
76+
return true;
77+
}
78+
79+
void Graph::EulerianPathHierholzerAlgorithm(Node* startingNode)
80+
{
81+
stack<Node*> currentPath;
82+
currentPath.push(startingNode);
83+
while (!currentPath.empty())
84+
{
85+
Node* currentNode = currentPath.top();
86+
if (!this->_adjlist[currentNode].empty())
87+
{
88+
Node* nextNode = this->_adjlist[currentNode].front();
89+
this->_adjlist[currentNode].pop_front();
90+
this->_adjlist[nextNode].remove(currentNode);
91+
currentPath.push(nextNode);
92+
}
93+
else
94+
{
95+
currentPath.pop();
96+
this->_eulerianPath.push_back(currentNode->data);
97+
}
98+
}
99+
}
100+
101+
// Graph Public Member Methods
102+
void Graph::PushUndirectedEdge(int valueU, int valueV)
103+
{
104+
Node* nodeU = this->MakeOrFindNode(valueU);
105+
Node* nodeV = this->MakeOrFindNode(valueV);
106+
107+
this->_adjlist[nodeU].push_back(nodeV);
108+
nodeU->degree++;
109+
this->_adjlist[nodeV].push_back(nodeU);
110+
nodeV->degree++;
111+
}
112+
113+
void Graph::PushDirectedEdge(int valueU, int valueV)
114+
{
115+
Node* nodeU = this->MakeOrFindNode(valueU);
116+
Node* nodeV = this->MakeOrFindNode(valueV);
117+
118+
this->_adjlist[nodeU].push_back(nodeV);
119+
nodeU->outDegree++;
120+
nodeV->inDegree++;
121+
}
122+
123+
void Graph::PushSingleNode(int valueU)
124+
{
125+
Node* nodeU = this->MakeOrFindNode(valueU);
126+
}
127+
128+
void Graph::FindEulerianPathAndCircuit()
129+
{
130+
// If the graph is not connected then graph G is Not-Eulerian.
131+
if (this->IsConnected() == false)
132+
{
133+
this->_isEulerianPathPresent = false;
134+
this->_isEulerianCircuitPresent = false;
135+
return;
136+
}
137+
138+
int oddDegreeVertexCount = 0;
139+
for (auto& iterator : this->_nodeMap)
140+
{
141+
if (iterator.second->degree & 1)
142+
{
143+
oddDegreeVertexCount++;
144+
}
145+
}
146+
147+
// Check-1 : When no vertex with odd degree is present, then graph G is Eulerian.
148+
if (oddDegreeVertexCount == 0)
149+
{
150+
this->_isEulerianPathPresent = true;
151+
this->_isEulerianCircuitPresent = true;
152+
return;
153+
}
154+
155+
// Check-2 : When 2 vertices have odd degree, then graph G is Semi-Eulerian.
156+
if (oddDegreeVertexCount == 2)
157+
{
158+
this->_isEulerianPathPresent = true;
159+
this->_isEulerianCircuitPresent = false;
160+
return;
161+
}
162+
163+
// Check-3 : When more than 2 vertices have odd degree, then graph G is Not Eulerian.
164+
if (oddDegreeVertexCount > 2)
165+
{
166+
this->_isEulerianPathPresent = false;
167+
this->_isEulerianCircuitPresent = false;
168+
return;
169+
}
170+
}
171+
172+
bool Graph::IsEulerianPathPresent()
173+
{
174+
return this->_isEulerianPathPresent;
175+
}
176+
177+
bool Graph::IsEulerianCircuitPresent()
178+
{
179+
return this->_isEulerianCircuitPresent;
180+
}
181+
182+
vector<int> Graph::UndirectedGraphGetEulerianPath()
183+
{
184+
// Case-3 : When more than 2 vertices have odd degree, then the graph G is not Eulerian.
185+
// No Eulerian Path is posible.
186+
if (this->_isEulerianPathPresent == false)
187+
{
188+
return {};
189+
}
190+
191+
// Now 2 cases remains.
192+
// Case-2 : When 2 vertices have odd degree. Choose any one of them.
193+
Node* node = nullptr;
194+
for (auto& iterator : this->_nodeMap)
195+
{
196+
if (iterator.second->degree & 1)
197+
{
198+
node = iterator.second;
199+
break;
200+
}
201+
}
202+
203+
// Case-1 : When no vertex with odd degree is present. Choose any vertex as starting point.
204+
if (node == nullptr)
205+
{
206+
node = this->_nodeMap[0];
207+
}
208+
this->EulerianPathHierholzerAlgorithm(node);
209+
reverse(this->_eulerianPath.begin(), this->_eulerianPath.end());
210+
return this->_eulerianPath;
211+
}
212+
}

SourceCodes/0003_Graph/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set(0003GRAPH_SOURCES
55
0003_TopologicalSort.cc
66
0004_StronglyConnectedComponents.cc
77
0005_HamiltonianPathAndCycle.cc
8+
0006_EulerianPathAndCircuit.cc
89
)
910

1011
# Create a library target
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include<gtest/gtest.h>
2+
#include "../Headers/0003_Graph/0006_EulerianPathAndCircuit.h"
3+
#include "../0000_CommonUtilities/UnitTestHelper.h"
4+
5+
namespace EulerianPathAndCircuit
6+
{
7+
UnitTestHelper unitTestHelper;
8+
9+
TEST(EulerianPathAndCycle, Test1)
10+
{
11+
Graph graph;
12+
13+
graph.PushUndirectedEdge(1, 0);
14+
graph.PushUndirectedEdge(0, 2);
15+
graph.PushUndirectedEdge(2, 1);
16+
graph.PushUndirectedEdge(0, 3);
17+
graph.PushUndirectedEdge(3, 4);
18+
graph.PushUndirectedEdge(4, 0);
19+
20+
graph.FindEulerianPathAndCircuit();
21+
22+
bool isEulerianPathPresent = graph.IsEulerianPathPresent();
23+
bool isEulerianCircuitPresent = graph.IsEulerianCircuitPresent();
24+
25+
vector<int> actualEulerianPath = graph.UndirectedGraphGetEulerianPath();
26+
vector<int> expectedEulerianPath = { 0, 1, 2, 0, 3, 4, 0};
27+
28+
ASSERT_TRUE(isEulerianPathPresent);
29+
ASSERT_TRUE(isEulerianCircuitPresent);
30+
EXPECT_EQ(expectedEulerianPath, actualEulerianPath);
31+
}
32+
}

Tests/0003_Graph/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_executable(
1717
0003_TopologicalSortTest.cc
1818
0004_StronglyConnectedComponentsTest.cc
1919
0005_HamiltonianPathAndCycleTest.cc
20+
0006_EulerianPathAndCircuitTest.cc
2021
)
2122

2223
target_link_libraries(

0 commit comments

Comments
 (0)