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
use pyo3::prelude::*;
use std::collections::{HashMap, VecDeque, HashSet};

/// Represents a graph using an adjacency list.
#[pyclass]
pub struct Graph {
    adjacency_list: HashMap<String, Vec<String>>,
}

#[pymethods]
impl Graph {
    /// Create a new empty graph.
    #[new]
    fn new() -> Self {
        Graph {
            adjacency_list: HashMap::new(),
        }
    }

    /// Add an edge to the graph.
    ///
    /// # Arguments
    ///
    /// * `src` - A string slice that holds the source vertex.
    /// * `dst` - A string slice that holds the destination vertex.
    fn add_edge(&mut self, src: &str, dst: &str) {
        self.adjacency_list
            .entry(src.to_string())
            .or_insert_with(Vec::new)
            .push(dst.to_string());
        self.adjacency_list
            .entry(dst.to_string())
            .or_insert_with(Vec::new)
            .push(src.to_string());
    }

    /// Perform a Depth-First Search (DFS) starting from a given vertex.
    ///
    /// # Arguments
    ///
    /// * `start` - A string slice that holds the starting vertex.
    ///
    /// # Returns
    ///
    /// A list of vertices in the order they were visited.
    fn dfs(&self, start: &str) -> Vec<String> {
        let mut visited = HashSet::new();
        let mut stack = vec![start.to_string()];
        let mut result = vec![];

        while let Some(node) = stack.pop() {
            if !visited.contains(&node) {
                visited.insert(node.clone());
                result.push(node.clone());

                if let Some(neighbors) = self.adjacency_list.get(&node) {
                    for neighbor in neighbors {
                        if !visited.contains(neighbor) {
                            stack.push(neighbor.clone());
                        }
                    }
                }
            }
        }

        result
    }

    /// Perform a Breadth-First Search (BFS) starting from a given vertex.
    ///
    /// # Arguments
    ///
    /// * `start` - A string slice that holds the starting vertex.
    ///
    /// # Returns
    ///
    /// A list of vertices in the order they were visited.
    fn bfs(&self, start: &str) -> Vec<String> {
        let mut visited = HashSet::new();
        let mut queue = VecDeque::new();
        let mut result = vec![];

        visited.insert(start.to_string());
        queue.push_back(start.to_string());

        while let Some(node) = queue.pop_front() {
            result.push(node.clone());

            if let Some(neighbors) = self.adjacency_list.get(&node) {
                for neighbor in neighbors {
                    if !visited.contains(neighbor) {
                        visited.insert(neighbor.clone());
                        queue.push_back(neighbor.clone());
                    }
                }
            }
        }

        result
    }
}

/// Create a new graph instance.
#[pyfunction]
fn create_graph() -> Graph {
    Graph::new()
}