Skip to content

Commit 69c76a3

Browse files
Add eulerian path to graph (TheAlgorithms#533)
1 parent a78d5d4 commit 69c76a3

File tree

2 files changed

+196
-0
lines changed

2 files changed

+196
-0
lines changed

src/graph/eulerian_path.rs

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
use std::collections::LinkedList;
2+
use std::vec::Vec;
3+
4+
/// Struct representing an Eulerian Path in a directed graph.
5+
pub struct EulerianPath {
6+
n: usize, // Number of nodes in the graph
7+
edge_count: usize, // Total number of edges in the graph
8+
in_degree: Vec<usize>, // In-degrees of nodes
9+
out_degree: Vec<usize>, // Out-degrees of nodes
10+
path: LinkedList<usize>, // Linked list to store the Eulerian path
11+
graph: Vec<Vec<usize>>, // Adjacency list representing the directed graph
12+
}
13+
14+
impl EulerianPath {
15+
/// Creates a new instance of EulerianPath.
16+
///
17+
/// # Arguments
18+
///
19+
/// * `graph` - A directed graph represented as an adjacency list.
20+
///
21+
/// # Returns
22+
///
23+
/// A new EulerianPath instance.
24+
pub fn new(graph: Vec<Vec<usize>>) -> Self {
25+
let n = graph.len();
26+
Self {
27+
n,
28+
edge_count: 0,
29+
in_degree: vec![0; n],
30+
out_degree: vec![0; n],
31+
path: LinkedList::new(),
32+
graph,
33+
}
34+
}
35+
36+
/// Finds an Eulerian path in the directed graph.
37+
///
38+
/// # Returns
39+
///
40+
/// An `Option` containing the Eulerian path if it exists, or `None` if no Eulerian path exists.
41+
pub fn find_eulerian_path(&mut self) -> Option<Vec<usize>> {
42+
self.initialize();
43+
44+
if !self.has_eulerian_path() {
45+
return None;
46+
}
47+
48+
let start_node = self.find_start_node();
49+
self.traverse(start_node);
50+
51+
if self.path.len() != self.edge_count + 1 {
52+
return None;
53+
}
54+
55+
let mut solution = Vec::with_capacity(self.edge_count + 1);
56+
while let Some(node) = self.path.pop_front() {
57+
solution.push(node);
58+
}
59+
60+
Some(solution)
61+
}
62+
63+
/// Initializes the degree vectors and counts the total number of edges in the graph.
64+
fn initialize(&mut self) {
65+
for (from, neighbors) in self.graph.iter().enumerate() {
66+
for &to in neighbors {
67+
self.in_degree[to] += 1;
68+
self.out_degree[from] += 1;
69+
self.edge_count += 1;
70+
}
71+
}
72+
}
73+
74+
/// Checks if the graph has an Eulerian path.
75+
///
76+
/// # Returns
77+
///
78+
/// `true` if an Eulerian path exists, `false` otherwise.
79+
fn has_eulerian_path(&self) -> bool {
80+
if self.edge_count == 0 {
81+
return false;
82+
}
83+
84+
let (mut start_nodes, mut end_nodes) = (0, 0);
85+
for i in 0..self.n {
86+
let in_degree = self.in_degree[i] as i32;
87+
let out_degree = self.out_degree[i] as i32;
88+
89+
if (out_degree - in_degree) > 1 || (in_degree - out_degree) > 1 {
90+
return false;
91+
} else if (out_degree - in_degree) == 1 {
92+
start_nodes += 1;
93+
} else if (in_degree - out_degree) == 1 {
94+
end_nodes += 1;
95+
}
96+
}
97+
98+
(end_nodes == 0 && start_nodes == 0) || (end_nodes == 1 && start_nodes == 1)
99+
}
100+
101+
/// Finds the starting node for the Eulerian path.
102+
///
103+
/// # Returns
104+
///
105+
/// The index of the starting node.
106+
fn find_start_node(&self) -> usize {
107+
let mut start = 0;
108+
for i in 0..self.n {
109+
if self.out_degree[i] - self.in_degree[i] == 1 {
110+
return i;
111+
}
112+
if self.out_degree[i] > 0 {
113+
start = i;
114+
}
115+
}
116+
start
117+
}
118+
119+
/// Traverses the graph to find the Eulerian path recursively.
120+
///
121+
/// # Arguments
122+
///
123+
/// * `at` - The current node being traversed.
124+
fn traverse(&mut self, at: usize) {
125+
while self.out_degree[at] != 0 {
126+
let next = self.graph[at][self.out_degree[at] - 1];
127+
self.out_degree[at] -= 1;
128+
self.traverse(next);
129+
}
130+
self.path.push_front(at);
131+
}
132+
}
133+
134+
#[cfg(test)]
135+
mod tests {
136+
use super::*;
137+
138+
/// Creates an empty graph with `n` nodes.
139+
fn create_empty_graph(n: usize) -> Vec<Vec<usize>> {
140+
vec![Vec::new(); n]
141+
}
142+
143+
/// Adds a directed edge from `from` to `to` in the graph.
144+
fn add_directed_edge(graph: &mut [Vec<usize>], from: usize, to: usize) {
145+
graph[from].push(to);
146+
}
147+
148+
#[test]
149+
fn good_path_test() {
150+
let n = 7;
151+
let mut graph = create_empty_graph(n);
152+
153+
add_directed_edge(&mut graph, 1, 2);
154+
add_directed_edge(&mut graph, 1, 3);
155+
add_directed_edge(&mut graph, 2, 2);
156+
add_directed_edge(&mut graph, 2, 4);
157+
add_directed_edge(&mut graph, 2, 4);
158+
add_directed_edge(&mut graph, 3, 1);
159+
add_directed_edge(&mut graph, 3, 2);
160+
add_directed_edge(&mut graph, 3, 5);
161+
add_directed_edge(&mut graph, 4, 3);
162+
add_directed_edge(&mut graph, 4, 6);
163+
add_directed_edge(&mut graph, 5, 6);
164+
add_directed_edge(&mut graph, 6, 3);
165+
166+
let mut solver = EulerianPath::new(graph);
167+
168+
assert_eq!(
169+
solver.find_eulerian_path().unwrap(),
170+
vec![1, 3, 5, 6, 3, 2, 4, 3, 1, 2, 2, 4, 6]
171+
);
172+
}
173+
174+
#[test]
175+
fn small_path_test() {
176+
let n = 5;
177+
let mut graph = create_empty_graph(n);
178+
179+
add_directed_edge(&mut graph, 0, 1);
180+
add_directed_edge(&mut graph, 1, 2);
181+
add_directed_edge(&mut graph, 1, 4);
182+
add_directed_edge(&mut graph, 1, 3);
183+
add_directed_edge(&mut graph, 2, 1);
184+
add_directed_edge(&mut graph, 4, 1);
185+
186+
let mut solver = EulerianPath::new(graph);
187+
188+
assert_eq!(
189+
solver.find_eulerian_path().unwrap(),
190+
vec![0, 1, 4, 1, 2, 1, 3]
191+
);
192+
}
193+
}

src/graph/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod depth_first_search_tic_tac_toe;
88
mod dijkstra;
99
mod dinic_maxflow;
1010
mod disjoint_set_union;
11+
mod eulerian_path;
1112
mod floyd_warshall;
1213
mod graph_enumeration;
1314
mod heavy_light_decomposition;
@@ -18,6 +19,7 @@ mod prufer_code;
1819
mod strongly_connected_components;
1920
mod topological_sort;
2021
mod two_satisfiability;
22+
2123
pub use self::astar::astar;
2224
pub use self::bellman_ford::bellman_ford;
2325
pub use self::bipartite_matching::BipartiteMatching;
@@ -28,6 +30,7 @@ pub use self::depth_first_search_tic_tac_toe::minimax;
2830
pub use self::dijkstra::dijkstra;
2931
pub use self::dinic_maxflow::DinicMaxFlow;
3032
pub use self::disjoint_set_union::DisjointSetUnion;
33+
pub use self::eulerian_path::EulerianPath;
3134
pub use self::floyd_warshall::floyd_warshall;
3235
pub use self::graph_enumeration::enumerate_graph;
3336
pub use self::heavy_light_decomposition::HeavyLightDecomposition;

0 commit comments

Comments
 (0)