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