Skip to content

Commit 93fc798

Browse files
committed
added dijkstra algorithm
1 parent f4f8bd5 commit 93fc798

File tree

9 files changed

+176
-20
lines changed

9 files changed

+176
-20
lines changed

src/java/sequential/graph/dfs/RecursiveDepthFirstTraversal.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public synchronized Collection<T> dfs(Map<T, List<T>> graph, T root) {
1717
explored = new LinkedHashSet<>();
1818

1919
var traversed = explore(root);
20-
20+
2121
clear();
2222
return traversed;
2323
}
@@ -37,6 +37,7 @@ private void clear() {
3737
graph = null;
3838
}
3939

40+
4041
public static void main(String[] args) {
4142
var graph = Map.of(
4243
"you", List.of("alice", "bob", "clair"),
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
java_binary(
2+
name = "dijkstra",
3+
main_class = "sequential.graph.dijkstra.Dijkstra",
4+
srcs = glob(["*.java"]),
5+
)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package sequential.graph.dijkstra;
2+
3+
import java.util.HashMap;
4+
import java.util.HashSet;
5+
import java.util.LinkedList;
6+
import java.util.List;
7+
import java.util.Map;
8+
import java.util.Set;
9+
10+
11+
class Dijkstra<T> {
12+
13+
private static final double INFINITY = Double.POSITIVE_INFINITY;
14+
15+
16+
public static <T> List<T> dijkstra(Map<T, Map<T, Double>> graph, T root, T target) {
17+
var rootSuccessors = graph.getOrDefault(root, Map.of());
18+
19+
var costs = new HashMap<>(rootSuccessors);
20+
var explored = new HashSet<T>();
21+
var parents = new HashMap<T, T>();
22+
for (var node : rootSuccessors.keySet())
23+
parents.put(node, root);
24+
25+
var node = findMinCostNode(costs, explored);
26+
while (node != null) {
27+
explored.add(node);
28+
var nodeCost = costs.get(node);
29+
30+
var successors = graph.getOrDefault(node, Map.of());
31+
32+
for (var succ : successors.keySet()) {
33+
var edgeWeight = successors.get(succ);
34+
if (nodeCost + edgeWeight < costs.getOrDefault(succ, INFINITY)) {
35+
costs.put(succ, nodeCost + edgeWeight);
36+
parents.put(succ, node);
37+
}
38+
}
39+
node = findMinCostNode(costs, explored);
40+
}
41+
42+
return buildPathToNode(target, parents);
43+
}
44+
45+
private static <T> T findMinCostNode(Map<T, Double> costs, Set<T> explored) {
46+
var minCost = INFINITY;
47+
T minCostNode = null;
48+
for (var node : costs.keySet()) {
49+
var cost = costs.get(node);
50+
if (!explored.contains(node) && cost < minCost) {
51+
minCost = cost;
52+
minCostNode = node;
53+
}
54+
}
55+
return minCostNode;
56+
}
57+
58+
private static <T> List<T> buildPathToNode(T target, Map<T, T> parents) {
59+
if (!parents.containsKey(target))
60+
throw new IllegalArgumentException("Invalid arguments provided.");
61+
62+
var path = new LinkedList<T>();
63+
T node = target;
64+
while (node != null) {
65+
path.add(0, node);
66+
node = parents.get(node);
67+
}
68+
return path;
69+
}
70+
71+
72+
public static void main(String[] args) {
73+
var graph = Map.of(
74+
"Start", Map.of("A", 5.0),
75+
"A", Map.of("B", 7.0, "C", 4.0),
76+
"B", Map.of("Finish", 4.0),
77+
"C", Map.of("Finish", 3.0)
78+
);
79+
80+
System.out.println(
81+
dijkstra(graph, "Start", "Finish")
82+
);
83+
}
84+
}

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

Whitespace-only changes.

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

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ fun <T> Graph<T>.dijkstra(root: T, target: T): Collection<T> {
2323
val explored = mutableSetOf<T>()
2424
val parents = graph[root].orEmpty().mapValues { root }.toMutableMap()
2525

26-
var node = costs.minCostNode(explored)
26+
var node = costs.findMinCostNode(explored)
2727
while (node != null) {
28+
explored += node
2829
val nodeCost = costs[node]!!
2930

3031
val successors = graph[node].orEmpty()
@@ -34,32 +35,27 @@ fun <T> Graph<T>.dijkstra(root: T, target: T): Collection<T> {
3435
parents[succ] = node
3536
}
3637
}
37-
explored += node
38-
node = costs.minCostNode(explored)
38+
node = costs.findMinCostNode(explored)
3939
}
4040

41-
return pathToNode(target, parents)
41+
return buildPathToNode(target, parents)
4242
}
4343

44-
private fun <T> Map<T, Double>.minCostNode(explored: Collection<T>): T? {
45-
val costs = this
46-
47-
var minCostNode: T? = null
48-
var minCost = INFINITY
49-
for ((node, cost) in costs) {
50-
if (node !in explored && cost < minCost) {
51-
minCostNode = node
52-
minCost = cost
53-
}
54-
}
55-
return minCostNode
56-
}
44+
private fun <T> Map<T, Double>.findMinCostNode(explored: Collection<T>): T? =
45+
// turning costs to sequence to improve performance of further operations.
46+
asSequence()
47+
// ignoring already explored nodes.
48+
.filter { (node, _) -> node !in explored }
49+
// finding the min cost node.
50+
.minBy { (_, cost) -> cost}
51+
// returning node object or `null` if the node was not found.
52+
?.key
5753

5854
/**
5955
* Build path from root to target node.
6056
*/
61-
private fun <T> pathToNode(target: T, parents: Map<T, T>): List<T> {
62-
if (target !in parents) return emptyList()
57+
private fun <T> buildPathToNode(target: T, parents: Map<T, T>): List<T> {
58+
if (target !in parents) error("Invalid arguments provided.")
6359

6460
val path = mutableListOf<T>()
6561
var node: T? = target
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_binary")
2+
3+
swift_binary(
4+
name = "dijkstra",
5+
srcs = [
6+
"Dijkstra.swift",
7+
"main.swift",
8+
],
9+
)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
typealias Graph<T: Hashable> = [T: [T: Double]]
2+
3+
4+
let infinity = Double.infinity
5+
6+
7+
func dijkstra<T>(in graph: Graph<T>, withRoot root: T, findPathTo target: T) -> [T]? {
8+
var costs = graph[root] ?? [:]
9+
var explored = Set<T>()
10+
var parents = graph[root]?.mapValues { cost in root } ?? [:]
11+
12+
while let node = findMinCostNode(from: costs, except: explored) {
13+
explored.insert(node)
14+
let nodeCost = costs[node]!
15+
16+
guard let successors = graph[node] else { continue }
17+
18+
for (succ, edgeWeight) in successors {
19+
if nodeCost + edgeWeight < costs[succ] ?? infinity {
20+
costs[succ] = nodeCost + edgeWeight
21+
parents[succ] = node
22+
}
23+
}
24+
}
25+
26+
return buildPathTo(target, with: parents)
27+
}
28+
29+
private func findMinCostNode<T>(from costs: [T: Double], except explored: Set<T>) -> T? {
30+
return costs
31+
.filter { node, cost in !explored.contains(node) }
32+
.min { a, b in a.value < b.value}?
33+
.key
34+
}
35+
36+
private func buildPathTo<T>(_ target: T, with parents: [T: T]) -> [T]? {
37+
guard parents[target] != nil else { return nil }
38+
39+
var path = [T]()
40+
var node: T? = target
41+
while node != nil {
42+
path.append(node!)
43+
node = parents[node!]
44+
}
45+
return path.reversed()
46+
}
47+
48+
49+
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]
55+
]
56+
57+
print(
58+
dijkstra(in: graph, withRoot: "Start", findPathTo: "Finish") ?? "Path not found!"
59+
)
60+
}

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

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mainDijkstra()

0 commit comments

Comments
 (0)