Skip to content

Commit 2a8227e

Browse files
committed
chore: improve naming
1 parent 6a6724a commit 2a8227e

File tree

1 file changed

+76
-76
lines changed

1 file changed

+76
-76
lines changed

src/graph/eulerian_path.rs

Lines changed: 76 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -3,150 +3,150 @@
33
//! path exists and, if so, constructs and returns the path.
44
55
use std::collections::LinkedList;
6-
use std::vec::Vec;
76

8-
/// Finds the Eulerian path in a directed graph represented by the number of nodes and edges.
7+
/// Finds an Eulerian path in a directed graph.
98
///
109
/// # Arguments
1110
///
12-
/// * `nodes` - The number of nodes in the graph.
13-
/// * `edges` - A vector of tuples representing the directed edges in the graph, where each tuple
14-
/// is of the form `(u, v)` indicating a directed edge from `u` to `v`.
15-
///
16-
/// The function checks if an Eulerian path exists and, if so, constructs and returns one valid path.
11+
/// * `node_count` - The number of nodes in the graph.
12+
/// * `edge_list` - A vector of tuples representing directed edges, where each tuple is of the form `(start, end)`.
1713
///
1814
/// # Returns
1915
///
20-
/// An `Option` containing a vector representing the Eulerian path if it exists, or `None` if no such path exists.
21-
pub fn find_eulerian_path(nodes: usize, edges: Vec<(usize, usize)>) -> Option<Vec<usize>> {
22-
let mut graph = vec![Vec::new(); nodes];
23-
for (u, v) in edges {
24-
graph[u].push(v);
16+
/// An `Option<Vec<usize>>` containing the Eulerian path if it exists; otherwise, `None`.
17+
pub fn find_eulerian_path(node_count: usize, edge_list: Vec<(usize, usize)>) -> Option<Vec<usize>> {
18+
let mut adjacency_list = vec![Vec::new(); node_count];
19+
for (start, end) in edge_list {
20+
adjacency_list[start].push(end);
2521
}
2622

27-
let mut solver = EulerianPath::new(graph);
28-
solver.find_eulerian_path()
23+
let mut eulerian_solver = EulerianPathSolver::new(adjacency_list);
24+
eulerian_solver.find_path()
2925
}
3026

31-
/// Struct representing an Eulerian path in a directed graph.
32-
pub struct EulerianPath {
33-
nodes: usize, // Number of nodes
34-
edges: usize, // Total number of edges
35-
in_deg: Vec<usize>, // In-degrees of nodes
36-
out_deg: Vec<usize>, // Out-degrees of nodes
37-
path: LinkedList<usize>, // Stores the Eulerian path
38-
graph: Vec<Vec<usize>>, // Adjacency list
27+
/// Struct to represent the solver for finding an Eulerian path in a directed graph.
28+
pub struct EulerianPathSolver {
29+
node_count: usize,
30+
edge_count: usize,
31+
in_degrees: Vec<usize>,
32+
out_degrees: Vec<usize>,
33+
eulerian_path: LinkedList<usize>,
34+
adjacency_list: Vec<Vec<usize>>,
3935
}
4036

41-
impl EulerianPath {
42-
/// Creates a new instance of `EulerianPath` for the given graph.
37+
impl EulerianPathSolver {
38+
/// Creates a new instance of `EulerianPathSolver`.
4339
///
4440
/// # Arguments
4541
///
46-
/// * `graph` - A directed graph represented as an adjacency list.
42+
/// * `adjacency_list` - The graph represented as an adjacency list.
4743
///
4844
/// # Returns
4945
///
50-
/// A new `EulerianPath` instance.
51-
pub fn new(graph: Vec<Vec<usize>>) -> Self {
46+
/// A new instance of `EulerianPathSolver`.
47+
pub fn new(adjacency_list: Vec<Vec<usize>>) -> Self {
5248
Self {
53-
nodes: graph.len(),
54-
edges: 0,
55-
in_deg: vec![0; graph.len()],
56-
out_deg: vec![0; graph.len()],
57-
path: LinkedList::new(),
58-
graph,
49+
node_count: adjacency_list.len(),
50+
edge_count: 0,
51+
in_degrees: vec![0; adjacency_list.len()],
52+
out_degrees: vec![0; adjacency_list.len()],
53+
eulerian_path: LinkedList::new(),
54+
adjacency_list,
5955
}
6056
}
6157

62-
/// Finds an Eulerian path if it exists.
58+
/// Computes the Eulerian path if it exists.
6359
///
6460
/// # Returns
6561
///
66-
/// An `Option` containing the Eulerian path as a vector if it exists, or `None` otherwise.
67-
fn find_eulerian_path(&mut self) -> Option<Vec<usize>> {
68-
self.init_degrees();
62+
/// An `Option<Vec<usize>>` containing the Eulerian path if found; otherwise, `None`.
63+
/// If multiple Eulerian paths exist, the one found will be returned, but it may not be unique.
64+
fn find_path(&mut self) -> Option<Vec<usize>> {
65+
self.initialize_degrees();
6966

7067
if !self.has_eulerian_path() {
7168
return None;
7269
}
7370

74-
let start = self.find_start();
75-
self.dfs(start);
71+
let start_node = self.get_start_node();
72+
self.depth_first_search(start_node);
7673

77-
if self.path.len() != self.edges + 1 {
74+
if self.eulerian_path.len() != self.edge_count + 1 {
7875
return None;
7976
}
8077

81-
let mut solution = Vec::with_capacity(self.edges + 1);
82-
while let Some(node) = self.path.pop_front() {
83-
solution.push(node);
78+
let mut path = Vec::with_capacity(self.edge_count + 1);
79+
while let Some(node) = self.eulerian_path.pop_front() {
80+
path.push(node);
8481
}
8582

86-
Some(solution)
83+
Some(path)
8784
}
8885

89-
/// Initializes in-degrees, out-degrees, and counts the total number of edges.
90-
fn init_degrees(&mut self) {
91-
for (u, neighbors) in self.graph.iter().enumerate() {
92-
for &v in neighbors {
93-
self.in_deg[v] += 1;
94-
self.out_deg[u] += 1;
95-
self.edges += 1;
86+
/// Initializes in-degrees and out-degrees for each node and counts total edges.
87+
fn initialize_degrees(&mut self) {
88+
for (start_node, neighbors) in self.adjacency_list.iter().enumerate() {
89+
for &end_node in neighbors {
90+
self.in_degrees[end_node] += 1;
91+
self.out_degrees[start_node] += 1;
92+
self.edge_count += 1;
9693
}
9794
}
9895
}
9996

100-
/// Checks if the graph has an Eulerian path.
97+
/// Checks if an Eulerian path is possible in the graph.
10198
///
10299
/// # Returns
103100
///
104-
/// `true` if an Eulerian path exists, `false` otherwise.
101+
/// `true` if an Eulerian path exists; otherwise, `false`.
105102
fn has_eulerian_path(&self) -> bool {
106-
if self.edges == 0 {
103+
if self.edge_count == 0 {
107104
return false;
108105
}
109106

110-
let (mut start, mut end) = (0, 0);
111-
for i in 0..self.nodes {
112-
let (in_deg, out_deg) = (self.in_deg[i] as isize, self.out_deg[i] as isize);
113-
match out_deg - in_deg {
114-
1 => start += 1,
115-
-1 => end += 1,
116-
d if d.abs() > 1 => return false,
107+
let (mut start_nodes, mut end_nodes) = (0, 0);
108+
for i in 0..self.node_count {
109+
let (in_degree, out_degree) =
110+
(self.in_degrees[i] as isize, self.out_degrees[i] as isize);
111+
match out_degree - in_degree {
112+
1 => start_nodes += 1,
113+
-1 => end_nodes += 1,
114+
degree_diff if degree_diff.abs() > 1 => return false,
117115
_ => (),
118116
}
119117
}
120118

121-
(start == 0 && end == 0) || (start == 1 && end == 1)
119+
(start_nodes == 0 && end_nodes == 0) || (start_nodes == 1 && end_nodes == 1)
122120
}
123121

124-
/// Finds the start node for the Eulerian path.
122+
/// Finds the starting node for the Eulerian path.
125123
///
126124
/// # Returns
127125
///
128-
/// The index of the start node.
129-
fn find_start(&self) -> usize {
130-
for i in 0..self.nodes {
131-
if self.out_deg[i] > self.in_deg[i] {
126+
/// The index of the starting node.
127+
fn get_start_node(&self) -> usize {
128+
for i in 0..self.node_count {
129+
if self.out_degrees[i] > self.in_degrees[i] {
132130
return i;
133131
}
134132
}
135-
(0..self.nodes).find(|&i| self.out_deg[i] > 0).unwrap_or(0)
133+
(0..self.node_count)
134+
.find(|&i| self.out_degrees[i] > 0)
135+
.unwrap_or(0)
136136
}
137137

138-
/// Depth-first search traversal to construct the Eulerian path.
138+
/// Performs depth-first search to construct the Eulerian path.
139139
///
140140
/// # Arguments
141141
///
142-
/// * `u` - The current node being traversed.
143-
fn dfs(&mut self, u: usize) {
144-
while self.out_deg[u] > 0 {
145-
let v = self.graph[u][self.out_deg[u] - 1];
146-
self.out_deg[u] -= 1;
147-
self.dfs(v);
142+
/// * `curr_node` - The current node being visited in the DFS traversal.
143+
fn depth_first_search(&mut self, curr_node: usize) {
144+
while self.out_degrees[curr_node] > 0 {
145+
let next_node = self.adjacency_list[curr_node][self.out_degrees[curr_node] - 1];
146+
self.out_degrees[curr_node] -= 1;
147+
self.depth_first_search(next_node);
148148
}
149-
self.path.push_front(u);
149+
self.eulerian_path.push_front(curr_node);
150150
}
151151
}
152152

0 commit comments

Comments
 (0)