use std::cmp::Reverse;
use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque};
use std::hash::Hash;
use std::rc::Rc;
use crate::data_structures::graph::Graph;
use crate::data_structures::tree::TreeNode;
pub fn breadth_first_search<T: Eq + Hash + Clone>(
graph: &Graph<T>,
start: Rc<TreeNode<T>>
) -> Vec<T> {
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
let mut result = Vec::new();
queue.push_back(Rc::clone(&start));
visited.insert(Rc::clone(&start));
while let Some(node) = queue.pop_front() {
result.push(node.value.clone());
if let Some(neighbors) = graph.graph.get(&node) {
for (neighbor, _) in neighbors {
if !visited.contains(neighbor) {
queue.push_back(Rc::clone(neighbor));
visited.insert(Rc::clone(neighbor));
}
}
}
}
result
}
pub fn depth_first_search<T: Eq + Hash + Clone>(
graph: &Graph<T>,
start: Rc<TreeNode<T>>
) -> Vec<T> {
let mut visited = HashSet::new();
let mut result = Vec::new();
depth_first_search_helper(graph, start, &mut visited, &mut result);
result
}
fn depth_first_search_helper<'a, T: Eq + Hash + Clone>(
graph: &'a Graph<T>,
node: Rc<TreeNode<T>>,
visited: &mut HashSet<Rc<TreeNode<T>>>,
result: &mut Vec<T>,
) {
if visited.contains(&node) {
return;
}
visited.insert(Rc::clone(&node));
result.push(node.value.clone());
if let Some(neighbors) = graph.graph.get(&node) {
for(neighbor, _) in neighbors {
depth_first_search_helper(graph, Rc::clone(neighbor), visited, result);
}
}
}
pub fn dijkstra<T: Eq + Hash + Clone + Ord>(
graph: &Graph<T>,
start: Rc<TreeNode<T>>
) -> HashMap<Rc<TreeNode<T>>, u32> {
let mut distances = HashMap::new();
let mut priority_queue = BinaryHeap::new();
distances.insert(Rc::clone(&start), 0);
priority_queue.push(Reverse((0, Rc::clone(&start))));
while let Some(Reverse((current_distance, current_node))) = priority_queue.pop() {
if current_distance < *distances.get(¤t_node).unwrap_or(&u32::MAX) {
continue;
}
if let Some(neighbors) = graph.graph.get(&*current_node) {
for (neighbor, weight) in neighbors {
if let Some(weight) = weight {
let new_distance = current_distance + *weight as u32;
if new_distance < *distances.get(neighbor).unwrap_or(&u32::MAX) {
distances.insert(neighbor.clone(), new_distance);
priority_queue.push(Reverse((new_distance, neighbor.clone())));
}
}
}
}
}
distances
}
pub fn bellman_ford<T: Eq + Hash + Clone + Ord>(
graph: &Graph<T>,
start: Rc<TreeNode<T>>
) -> Result<HashMap<Rc<TreeNode<T>>, i32>, String> {
let mut distances = HashMap::new();
distances.insert(Rc::clone(&start), 0);
let num_vertices: i32 = graph.graph.len() as i32;
for _ in 0..num_vertices - 1 {
let mut updates = Vec::new();
for (node, neighbors) in &graph.graph {
if let Some(current_distance) = distances.get(node) {
for (neighbor, weight) in neighbors {
let new_distance = current_distance + weight.unwrap();
updates.push((neighbor, new_distance));
}
}
}
for (neighbor, new_distance) in updates {
let existing_distance = distances.entry(Rc::clone(neighbor)).or_insert(i32::MAX);
if new_distance < *existing_distance {
*existing_distance = new_distance;
}
}
}
for (node, neighbors) in &graph.graph {
if let Some(¤t_distance) = distances.get(node) {
for (neighbor, weight) in neighbors {
let new_distance = current_distance + weight.unwrap();
if let Some(existing_distance) = distances.get(neighbor) {
if new_distance < *existing_distance {
return Err("Graph contains a negative weight cycle! \
Bellman-Ford will not be accurate for this graph".to_string());
}
}
}
}
}
Ok(distances)
}