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
108
109
110
111
112
113
114
115
116
117
use std::{collections::HashSet, vec};
use std::fmt::Debug;
use crate::priority_queue::PriorityQueue;

/// Dijkstra algorithm
///
/// This crate implements a Dijkstra algorithm to compute the shortest path by given graph.
/// 
#[derive(Debug)]
pub struct Dijkstra {
    adjacent_list: Vec<Vec<(usize, usize)>>,
    num_nodes: usize,
}

impl Dijkstra {
    /// Create a new Dijkstra graph with edges(tuple) Vec
    /// 
    /// # Example
    /// 
    /// ```
    /// use flex_algo::Dijkstra;
    /// 
    /// let times = vec![(1, 2, 9), (1, 4, 2), (2, 5, 1), (4, 2, 4), (4, 5, 6), (3, 2, 3), (5, 3, 7), (3, 1, 5)];
    /// let dijkstra = Dijkstra::new(5, times);
    /// 
    /// ```
    pub fn new(num_nodes: usize, edges: Vec<(usize, usize, usize)>) -> Self {
        let mut adjacent_list = vec![Vec::new(); num_nodes];
        for edge in edges {
            let source = edge.0 - 1;
            let target = edge.1 - 1;
            adjacent_list[source].push((target, edge.2));
        }
        Dijkstra {
            adjacent_list,
            num_nodes,
        }
    }

    /// Return the shortest path
    /// 
    /// # Example
    /// 
    /// ```
    /// use flex_algo::Dijkstra;
    /// 
    /// let times = vec![(1, 2, 9), (1, 4, 2), (2, 5, 1), (4, 2, 4), (4, 5, 6), (3, 2, 3), (5, 3, 7), (3, 1, 5)];
    /// let dijkstra = Dijkstra::new(5, times);
    /// let (max, path) =  dijkstra.shortest_path(1).unwrap();
    /// println!("shortest path: {:?}", path);
    /// assert_eq!(max, 14);
    /// 
    /// ```
    pub fn shortest_path(&self, node: usize) -> Option<(usize, Vec<usize>)> {
        let mut distances = vec![usize::MAX; self.num_nodes];
        distances[node-1] = 0;
        let distances_ptr = distances.as_mut_ptr();
        let mut heap = PriorityQueue::new(|a: &usize,b:&usize| distances.get(*a).cloned() < distances.get(*b).cloned());
        let mut seens = HashSet::new();
        let mut visit = Vec::new();
        heap.push(node-1);

        while !heap.is_empty() {
            let vertex = heap.pop().unwrap();
            if !seens.contains(&vertex) {
                visit.push(vertex);
                seens.insert(vertex);
                let adjacent = &self.adjacent_list[vertex];
                for pair in adjacent {
                    let neighbor_vertex = pair.0;
                    let weight = pair.1;
                    if distances[vertex] + weight < distances[neighbor_vertex] {
                        unsafe {
                            *distances_ptr.add(neighbor_vertex) = distances[vertex] + weight;
                        }
                        heap.push(neighbor_vertex);
                    }
                }
            }
        }
        distances.sort();
        let max = distances.pop().unwrap();
        if max < usize::MAX {
            return Some((max, visit));
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use std::path;

    use super::*;

    #[test]
    fn test_dijkstra() {
        let times = vec![
            (1, 2, 9), (1, 4, 2), (2, 5, 1), (4, 2, 4), (4, 5, 6), (3, 2, 3), (5, 3, 7), (3, 1, 5)
        ];
        let dijkstra = Dijkstra::new(5, times);
        println!("Dijkstra: {:?}", dijkstra);
        // panic!()
    }

    #[test]
    fn test_shortest_path() {
        let times = vec![
            (1, 2, 9), (1, 4, 2), (2, 5, 1), (4, 2, 4), (4, 5, 6), (3, 2, 3), (5, 3, 7), (3, 1, 5)
        ];
        let dijkstra = Dijkstra::new(5, times);
        let (max, path) =  dijkstra.shortest_path(1).unwrap();
        println!("shortest path: {:?}", path);
        assert_eq!(max, 14);
        // panic!();
    }
}