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
+ }
0 commit comments