Skip to content

Commit f330170

Browse files
committed
improved dijkstra
1 parent 93fc798 commit f330170

File tree

6 files changed

+118
-21
lines changed

6 files changed

+118
-21
lines changed

src/java/sequential/graph/dijkstra/Dijkstra.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ class Dijkstra<T> {
1212

1313
private static final double INFINITY = Double.POSITIVE_INFINITY;
1414

15-
15+
1616
public static <T> List<T> dijkstra(Map<T, Map<T, Double>> graph, T root, T target) {
17-
var rootSuccessors = graph.getOrDefault(root, Map.of());
17+
if(!graph.containsKey(root)) throw new IllegalArgumentException("Invalid root.");
1818

19-
var costs = new HashMap<>(rootSuccessors);
19+
var costs = new HashMap<>(graph.get(root));
2020
var explored = new HashSet<T>();
2121
var parents = new HashMap<T, T>();
22-
for (var node : rootSuccessors.keySet())
22+
for (var node : graph.get(root).keySet())
2323
parents.put(node, root);
2424

2525
var node = findMinCostNode(costs, explored);
@@ -56,8 +56,7 @@ private static <T> T findMinCostNode(Map<T, Double> costs, Set<T> explored) {
5656
}
5757

5858
private static <T> List<T> buildPathToNode(T target, Map<T, T> parents) {
59-
if (!parents.containsKey(target))
60-
throw new IllegalArgumentException("Invalid arguments provided.");
59+
if (!parents.containsKey(target)) throw new IllegalArgumentException("Invalid target.");
6160

6261
var path = new LinkedList<T>();
6362
T node = target;

src/kotlin/sequential/graph/dijkstra/Dijkstra.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ private val INFINITY = Double.POSITIVE_INFINITY
1818
*/
1919
fun <T> Graph<T>.dijkstra(root: T, target: T): Collection<T> {
2020
val graph = this
21+
require(root in graph) { "Invalid root." }
2122

22-
val costs = graph[root].orEmpty().toMutableMap()
23+
val costs = graph[root]!!.toMutableMap()
2324
val explored = mutableSetOf<T>()
24-
val parents = graph[root].orEmpty().mapValues { root }.toMutableMap()
25+
val parents = graph[root]!!.mapValues { root }.toMutableMap()
2526

2627
var node = costs.findMinCostNode(explored)
2728
while (node != null) {
@@ -55,7 +56,7 @@ private fun <T> Map<T, Double>.findMinCostNode(explored: Collection<T>): T? =
5556
* Build path from root to target node.
5657
*/
5758
private fun <T> buildPathToNode(target: T, parents: Map<T, T>): List<T> {
58-
if (target !in parents) error("Invalid arguments provided.")
59+
require(target in parents) { "Invalid target."}
5960

6061
val path = mutableListOf<T>()
6162
var node: T? = target
@@ -68,14 +69,14 @@ private fun <T> buildPathToNode(target: T, parents: Map<T, T>): List<T> {
6869

6970

7071
fun main() {
71-
val waypoints: Graph<String> = mapOf(
72+
val graph: Graph<String> = mapOf(
7273
"Start" to mapOf("A" to 5.0),
7374
"A" to mapOf("B" to 7.0, "C" to 4.0),
7475
"B" to mapOf("Finish" to 4.0),
7576
"C" to mapOf("Finish" to 3.0)
7677
)
7778

7879
println(
79-
waypoints.dijkstra("Start", "Finish")
80+
graph.dijkstra("Start", "Finish")
8081
)
8182
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
py_binary(
2+
name = "dijkstra",
3+
main = "dijkstra.py",
4+
srcs = glob(["*.py"]),
5+
)

src/python/sequential/graph/dijkstra/README.md

Whitespace-only changes.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
infinity = float("inf")
2+
3+
4+
def dijkstra(graph, root, target):
5+
if root not in graph:
6+
return None
7+
8+
costs = graph[root]
9+
explored = set()
10+
parents = {node: root for node in graph[root]}
11+
12+
node = find_min_cost_node(costs, explored)
13+
while node:
14+
explored.add(node)
15+
node_cost = costs[node]
16+
17+
successors = graph.get(node, {})
18+
for (succ, edge_cost) in successors.items():
19+
if node_cost + edge_cost < costs.get(succ, infinity):
20+
costs[succ] = node_cost + edge_cost
21+
parents[succ] = node
22+
23+
node = find_min_cost_node(costs, explored)
24+
25+
return build_path_to_node(target, parents)
26+
27+
28+
def find_min_cost_node(costs, explored):
29+
costs = {node: cost for (node, cost) in costs.items() if node not in explored}
30+
return min(costs, key=costs.get, default=None)
31+
32+
def build_path_to_node(target, parents):
33+
if target not in parents:
34+
return None
35+
36+
path = []
37+
node = target
38+
while node:
39+
path.append(node)
40+
node = parents.get(node)
41+
return path[::-1]
42+
43+
44+
def main():
45+
graph = {
46+
"Start": {"A": 5},
47+
"A": {"B": 7, "C": 4},
48+
"B": {"Finish": 4},
49+
"C": {"Finish": 3},
50+
}
51+
52+
print(
53+
dijkstra(graph, "Start", "Finish")
54+
)
55+
56+
if __name__ == "__main__":
57+
main()

src/swift/sequential/graph/dijkstra/Dijkstra.swift

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
1+
/// Weighted graph representation using dictionary.
12
typealias Graph<T: Hashable> = [T: [T: Double]]
23

34

5+
/// Infinity as a default node cost value.
46
let infinity = Double.infinity
57

68

9+
/**
10+
Finds fastest path between specified nodes in the given graph.
11+
12+
- Parameters:
13+
- graph: Given graph.
14+
- root: Beginning of the path.
15+
- target: End of the path.
16+
17+
- Returns: Array representing path to the `target` node starting from `root` or `nil` if invalid arguments provided.
18+
*/
719
func dijkstra<T>(in graph: Graph<T>, withRoot root: T, findPathTo target: T) -> [T]? {
8-
var costs = graph[root] ?? [:]
20+
guard graph[root] != nil else { return nil }
21+
22+
var costs = graph[root]!
923
var explored = Set<T>()
10-
var parents = graph[root]?.mapValues { cost in root } ?? [:]
24+
var parents = graph[root]!.mapValues { _ in root }
1125

12-
while let node = findMinCostNode(from: costs, except: explored) {
26+
while let node = findMinCostNode(in: costs, except: explored) {
1327
explored.insert(node)
1428
let nodeCost = costs[node]!
1529

@@ -26,13 +40,34 @@ func dijkstra<T>(in graph: Graph<T>, withRoot root: T, findPathTo target: T) ->
2640
return buildPathTo(target, with: parents)
2741
}
2842

29-
private func findMinCostNode<T>(from costs: [T: Double], except explored: Set<T>) -> T? {
43+
/**
44+
Finds the cheapest node at the given moment.
45+
46+
- Parameters:
47+
- costs: Dictionary which contains costs of all nodes at the given moment.
48+
- explored: Ignored nodes which are already explored.
49+
50+
- Returns: Min cost node at the given moment or `nil` if all nodes are already explored.
51+
*/
52+
private func findMinCostNode<T>(in costs: [T: Double], except explored: Set<T>) -> T? {
3053
return costs
54+
// ignoring already explored nodes.
3155
.filter { node, cost in !explored.contains(node) }
32-
.min { a, b in a.value < b.value}?
56+
// finding the min cost node. `value` corresponds to node cost.
57+
.min { cost1, cost2 in cost1.value < cost2.value}?
58+
// returning node object or `nil` if the node was not found.
3359
.key
3460
}
3561

62+
/**
63+
Builds a path to the given node starting from root.
64+
65+
- Parameters:
66+
- target: Given node which represends the end of the path.
67+
- parents: Dictionary which contains parents of all graph nodes.
68+
69+
- Returns: Array representing path to the `target` node starting from `root` or `nil` if invalid arguments provided.
70+
*/
3671
private func buildPathTo<T>(_ target: T, with parents: [T: T]) -> [T]? {
3772
guard parents[target] != nil else { return nil }
3873

@@ -47,11 +82,11 @@ private func buildPathTo<T>(_ target: T, with parents: [T: T]) -> [T]? {
4782

4883

4984
func mainDijkstra() {
50-
let graph: Graph<String> = [
51-
"Start": ["A": 5],
52-
"A": ["B": 7, "C": 4],
53-
"B": ["Finish": 4],
54-
"C": ["Finish": 3]
85+
let graph = [
86+
"Start": ["A": 5.0],
87+
"A": ["B": 7.0, "C": 4.0],
88+
"B": ["Finish": 4.0],
89+
"C": ["Finish": 3.0]
5590
]
5691

5792
print(

0 commit comments

Comments
 (0)