-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathDirectedEulerianPath.h
138 lines (122 loc) · 4.16 KB
/
DirectedEulerianPath.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#ifndef CH4_DIRECTEDEULERIANPATH_H
#define CH4_DIRECTEDEULERIANPATH_H
#include "../head/Digraph.h"
#include <iostream>
using std::cout;
using std::endl;
/**
* The {@code DirectedEulerianPath} class represents a data type
* for finding an Eulerian path in a digraph.
* An <em>Eulerian path</em> is a path (not necessarily simple) that
* uses every edge in the digraph exactly once.
* <p>
* This implementation uses a nonrecursive depth-first search.
* The constructor runs in O(E + V) time, and uses O(V) extra space,
* where E is the number of edges and V the number of vertices
* All other methods take O(1) time.
* <p>
* To compute Eulerian cycles in digraphs, see {@link DirectedEulerianCycle}.
* To compute Eulerian cycles and paths in undirected graphs, see
* {@link EulerianCycle} and {@link EulerianPath}.
* <p>
* For additional documentation,
* see <a href="https://algs4.cs.princeton.edu/42digraph">Section 4.2</a> of
* <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin Wayne.
*
* @author Robert Sedgewick
* @author Kevin Wayne
* @author Nate Liu
*/
class DirectedEulerianPath {
public:
/**
* Computes an Eulerian path in the specified digraph, if one exists.
*
* @param G the digraph
*/
DirectedEulerianPath(Digraph &G) {
// find vertex from which to start potential Eulerian path:
// a vertex v with outdegree(v) > indegree(v) if it exits;
// otherwise a vertex with outdegree(v) > 0
int deficit = 0;
int s = nonIsolatedVertex(G);
for (int v = 0; v < G.getV(); v++) {
if (G.outdegree(v) > G.getindegree(v)) {
deficit += (G.outdegree(v) - G.getindegree(v));
s = v;
}
}
// digraph can't have an Eulerian path
// (this condition is needed)
if (deficit > 1) return;
// special case for digraph with zero edges (has a degenerate Eulerian path)
if (s == -1) s = 0;
// create local view of adjacency lists, to iterate one vertex at a time
vector<forward_list<int>> adj(G.getV());
for (int v = 0; v < G.getV(); v++)
adj[v] = G.getadj(v);
// greedily add to cycle, depth-first search style
stack<int> stack1;
stack1.push(s);
while (!stack1.empty()) {
int v = stack1.top();
stack1.pop();
while (!adj[v].empty()) {
stack1.push(v);
auto tmp = v;
v = adj[v].front();
adj[tmp].pop_front();
}
// push vertex with no more available edges to path
path.push_front(v);
}
// check if all edges have been used
if (distance(path.begin(), path.end()) != G.getE() + 1)
path.clear();
}
/**
* Returns the sequence of vertices on an Eulerian path.
*
* @return the sequence of vertices on an Eulerian path;
* {@code null} if no such path
*/
forward_list<int> getpath() {
return path;
}
/**
* Returns true if the digraph has an Eulerian path.
*
* @return {@code true} if the digraph has an Eulerian path;
* {@code false} otherwise
*/
bool hasEulerianPath() {
return !path.empty();
}
static void unitTest(Digraph &G, string description) {
cout << description << endl;
cout << "-------------------------------------" << endl;
cout << G;
DirectedEulerianPath *euler = new DirectedEulerianPath(G);
cout << "Eulerian path: ";
if (euler->hasEulerianPath()) {
for (int v : euler->getpath()) {
cout << v << " ";
}
cout << endl;
} else {
cout << "none" << endl;
}
cout << endl;
}
private:
// returns any non-isolated vertex; -1 if no such vertex
static int nonIsolatedVertex(Digraph &G) {
for (int v = 0; v < G.getV(); v++)
if (G.outdegree(v) > 0)
return v;
return -1;
}
private:
forward_list<int> path; // Eulerian path; null if no suh path
};
#endif //CH4_DIRECTEDEULERIANPATH_H