广度优先搜索

  1. use std::collections::HashSet;
  2. use std::collections::VecDeque;
  3. /// Perform a breadth-first search on Graph `graph`.
  4. ///
  5. /// # Parameters
  6. ///
  7. /// - `graph`: The graph to search.
  8. /// - `root`: The starting node of the graph from which to begin searching.
  9. /// - `target`: The target node for the search.
  10. ///
  11. /// # Returns
  12. ///
  13. /// If the target is found, an Optional vector is returned with the history
  14. /// of nodes visited as its contents.
  15. ///
  16. /// If the target is not found or there is no path from the root,
  17. /// `None` is returned.
  18. ///
  19. pub fn breadth_first_search(graph: &Graph, root: Node, target: Node) -> Option<Vec<u32>> {
  20. let mut visited: HashSet<Node> = HashSet::new();
  21. let mut history: Vec<u32> = Vec::new();
  22. let mut queue = VecDeque::new();
  23. visited.insert(root);
  24. queue.push_back(root);
  25. while let Some(currentnode) = queue.pop_front() {
  26. history.push(currentnode.value());
  27. // If we reach the goal, return our travel history.
  28. if currentnode == target {
  29. return Some(history);
  30. }
  31. // Check the neighboring nodes for any that we've not visited yet.
  32. for neighbor in currentnode.neighbors(graph) {
  33. if !visited.contains(&neighbor) {
  34. visited.insert(neighbor);
  35. queue.push_back(neighbor);
  36. }
  37. }
  38. }
  39. // All nodes were visited, yet the target was not found.
  40. None
  41. }
  42. // Data Structures
  43. #[derive(Copy, Clone, PartialEq, Eq, Hash)]
  44. pub struct Node(u32);
  45. #[derive(Copy, Clone, PartialEq, Eq, Hash)]
  46. pub struct Edge(u32, u32);
  47. #[derive(Clone)]
  48. pub struct Graph {
  49. nodes: Vec<Node>,
  50. edges: Vec<Edge>,
  51. }
  52. impl Graph {
  53. pub fn new(nodes: Vec<Node>, edges: Vec<Edge>) -> Self {
  54. Graph { nodes, edges }
  55. }
  56. }
  57. impl From<u32> for Node {
  58. fn from(item: u32) -> Self {
  59. Node(item)
  60. }
  61. }
  62. impl Node {
  63. pub fn value(&self) -> u32 {
  64. self.0
  65. }
  66. pub fn neighbors(&self, graph: &Graph) -> Vec<Node> {
  67. graph
  68. .edges
  69. .iter()
  70. .filter(|e| e.0 == self.0)
  71. .map(|e| e.1.into())
  72. .collect()
  73. }
  74. }
  75. impl From<(u32, u32)> for Edge {
  76. fn from(item: (u32, u32)) -> Self {
  77. Edge(item.0, item.1)
  78. }
  79. }
  80. #[cfg(test)]
  81. mod tests {
  82. use super::*;
  83. /* Example graph #1:
  84. *
  85. * (1) <--- Root
  86. * / \
  87. * (2) (3)
  88. * / | | \
  89. * (4) (5) (6) (7)
  90. * |
  91. * (8)
  92. */
  93. fn graph1() -> Graph {
  94. let nodes = vec![1, 2, 3, 4, 5, 6, 7];
  95. let edges = vec![(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7), (5, 8)];
  96. Graph::new(
  97. nodes.into_iter().map(|v| v.into()).collect(),
  98. edges.into_iter().map(|e| e.into()).collect(),
  99. )
  100. }
  101. #[test]
  102. fn breadth_first_search_graph1_when_node_not_found_returns_none() {
  103. let graph = graph1();
  104. let root = 1;
  105. let target = 10;
  106. assert_eq!(
  107. breadth_first_search(&graph, root.into(), target.into()),
  108. None
  109. );
  110. }
  111. #[test]
  112. fn breadth_first_search_graph1_when_target_8_should_evaluate_all_nodes_first() {
  113. let graph = graph1();
  114. let root = 1;
  115. let target = 8;
  116. let expected_path = vec![1, 2, 3, 4, 5, 6, 7, 8];
  117. assert_eq!(
  118. breadth_first_search(&graph, root.into(), target.into()),
  119. Some(expected_path)
  120. );
  121. }
  122. /* Example graph #2:
  123. *
  124. * (1) --- (2) (3) --- (4)
  125. * / | / /
  126. * / | / /
  127. * / | / /
  128. * (5) (6) --- (7) (8)
  129. */
  130. fn graph2() -> Graph {
  131. let nodes = vec![1, 2, 3, 4, 5, 6, 7, 8];
  132. let undirected_edges = vec![
  133. (1, 2),
  134. (2, 1),
  135. (2, 5),
  136. (5, 2),
  137. (2, 6),
  138. (6, 2),
  139. (3, 4),
  140. (4, 3),
  141. (3, 6),
  142. (6, 3),
  143. (4, 7),
  144. (7, 4),
  145. (6, 7),
  146. (7, 6),
  147. ];
  148. Graph::new(
  149. nodes.into_iter().map(|v| v.into()).collect(),
  150. undirected_edges.into_iter().map(|e| e.into()).collect(),
  151. )
  152. }
  153. #[test]
  154. fn breadth_first_search_graph2_when_no_path_to_node_returns_none() {
  155. let graph = graph2();
  156. let root = 8;
  157. let target = 4;
  158. assert_eq!(
  159. breadth_first_search(&graph, root.into(), target.into()),
  160. None
  161. );
  162. }
  163. #[test]
  164. fn breadth_first_search_graph2_should_find_path_from_4_to_1() {
  165. let graph = graph2();
  166. let root = 4;
  167. let target = 1;
  168. let expected_path = vec![4, 3, 7, 6, 2, 1];
  169. assert_eq!(
  170. breadth_first_search(&graph, root.into(), target.into()),
  171. Some(expected_path)
  172. );
  173. }
  174. }