reorg and add code for second edition
This commit is contained in:
76
09_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js
Normal file
76
09_dijkstras_algorithm/ES6/01_dijkstras_algorithm.js
Normal file
@@ -0,0 +1,76 @@
|
||||
// the graph
|
||||
const graph = {};
|
||||
graph.start = {};
|
||||
graph.start.a = 6;
|
||||
graph.start.b = 2;
|
||||
|
||||
graph.a = {};
|
||||
graph.a.fin = 1;
|
||||
|
||||
graph.b = {};
|
||||
graph.b.a = 3;
|
||||
graph.b.fin = 5;
|
||||
|
||||
graph.fin = {};
|
||||
|
||||
// The costs table
|
||||
const costs = {};
|
||||
costs.a = 6;
|
||||
costs.b = 2;
|
||||
costs.fin = Infinity;
|
||||
|
||||
// the parents table
|
||||
const parents = {};
|
||||
parents.a = "start";
|
||||
parents.b = "start";
|
||||
parents.fin = null;
|
||||
|
||||
let processed = [];
|
||||
|
||||
/**
|
||||
* Find the lowest node
|
||||
* @param {Object} itCosts Hash table
|
||||
* @returns {(string|null)} The lowest node
|
||||
*/
|
||||
const findLowestCostNode = itCosts => {
|
||||
let lowestCost = Infinity;
|
||||
let lowestCostNode = null;
|
||||
|
||||
Object.keys(itCosts).forEach(node => {
|
||||
const cost = itCosts[node];
|
||||
// If it's the lowest cost so far and hasn't been processed yet...
|
||||
if (cost < lowestCost && !processed.includes(node)) {
|
||||
// ... set it as the new lowest-cost node.
|
||||
lowestCost = cost;
|
||||
lowestCostNode = node;
|
||||
}
|
||||
});
|
||||
return lowestCostNode;
|
||||
};
|
||||
|
||||
let node = findLowestCostNode(costs);
|
||||
|
||||
while (node !== null) {
|
||||
const cost = costs[node];
|
||||
// Go through all the neighbors of this node
|
||||
const neighbors = graph[node];
|
||||
Object.keys(neighbors).forEach(n => {
|
||||
const newCost = cost + neighbors[n];
|
||||
// If it's cheaper to get to this neighbor by going through this node
|
||||
if (costs[n] > newCost) {
|
||||
// ... update the cost for this node
|
||||
costs[n] = newCost;
|
||||
// This node becomes the new parent for this neighbor.
|
||||
parents[n] = node;
|
||||
}
|
||||
});
|
||||
|
||||
// Mark the node as processed
|
||||
processed.push(node);
|
||||
|
||||
// Find the next node to process, and loop
|
||||
node = findLowestCostNode(costs);
|
||||
}
|
||||
|
||||
console.log("Cost from the start to each node:");
|
||||
console.log(costs); // { a: 5, b: 2, fin: 6 }
|
||||
94
09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go
Normal file
94
09_dijkstras_algorithm/Golang/01_dijkstras_algorithm.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
var graph map[string]map[string]float64
|
||||
var costs map[string]float64
|
||||
var parents map[string]string
|
||||
var processed []string
|
||||
|
||||
func main() {
|
||||
// the graph
|
||||
graph = make(map[string]map[string]float64)
|
||||
graph["start"] = make(map[string]float64)
|
||||
graph["start"]["a"] = 6
|
||||
graph["start"]["b"] = 2
|
||||
|
||||
graph["a"] = make(map[string]float64)
|
||||
graph["a"]["fin"] = 1
|
||||
|
||||
graph["b"] = make(map[string]float64)
|
||||
graph["b"]["a"] = 3
|
||||
graph["b"]["fin"] = 5
|
||||
|
||||
graph["fin"] = make(map[string]float64)
|
||||
|
||||
// the costs table
|
||||
costs = make(map[string]float64)
|
||||
costs["a"] = 6
|
||||
costs["b"] = 2
|
||||
costs["fin"] = math.Inf(1)
|
||||
|
||||
// the parents table
|
||||
parents = make(map[string]string)
|
||||
parents["a"] = "start"
|
||||
parents["b"] = "start"
|
||||
parents["fin"] = ""
|
||||
|
||||
// Find the lowest-cost node that you haven't processed yet.
|
||||
node := find_lowest_cost_node(costs)
|
||||
// If you've processed all the nodes, this while loop is done.
|
||||
|
||||
for node != "" {
|
||||
cost := costs[node]
|
||||
// Go through all the neighbors of this node.
|
||||
neighbors := graph[node]
|
||||
|
||||
for node, _ := range neighbors {
|
||||
new_cost := cost + neighbors[node]
|
||||
// If it's cheaper to get to this neighbor by going through this node...
|
||||
if costs[node] > new_cost {
|
||||
// ... update the cost for this node.
|
||||
costs[node] = new_cost
|
||||
// This node becomes the new parent for this neighbor.
|
||||
parents[node] = node
|
||||
}
|
||||
}
|
||||
// Mark the node as processed.
|
||||
processed = append(processed, node)
|
||||
// Find the next node to process, and loop.
|
||||
node = find_lowest_cost_node(costs)
|
||||
}
|
||||
|
||||
fmt.Println(costs)
|
||||
|
||||
}
|
||||
|
||||
func find_lowest_cost_node(costs map[string]float64) string {
|
||||
lowest_cost := math.Inf(1)
|
||||
lowest_cost_node := ""
|
||||
|
||||
for node, _ := range costs {
|
||||
// fmt.Println("Node:", node, "Value:", value)
|
||||
cost := costs[node]
|
||||
// If it's the lowest cost so far and hasn't been processed yet...
|
||||
if cost < lowest_cost && !contains(processed, node) {
|
||||
// ... set it as the new lowest-cost node.
|
||||
lowest_cost = cost
|
||||
lowest_cost_node = node
|
||||
}
|
||||
}
|
||||
return lowest_cost_node
|
||||
}
|
||||
|
||||
func contains(s []string, e string) bool {
|
||||
for _, a := range s {
|
||||
if a == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
94
09_dijkstras_algorithm/Haskell/01_dijkstras_algorithm.hs
Normal file
94
09_dijkstras_algorithm/Haskell/01_dijkstras_algorithm.hs
Normal file
@@ -0,0 +1,94 @@
|
||||
import Data.List
|
||||
import Control.Applicative
|
||||
import qualified Data.HashMap.Strict as Map
|
||||
|
||||
type Costs = Map.HashMap String Double
|
||||
type Parents = Map.HashMap String String
|
||||
type WeightedEdge = (String, Double)
|
||||
|
||||
inf = read "Infinity" :: Double
|
||||
|
||||
graph = Map.fromList [
|
||||
("book", [("rarelp", 5.0), ("poster", 0.0)]),
|
||||
("rarelp", [("guitar", 15.0), ("drumset", 20.0)]),
|
||||
("poster", [("drumset", 35.0), ("guitar", 30.0)]),
|
||||
("drumset", [("piano", 10.0)]),
|
||||
("guitar", [("piano", 20.0)]),
|
||||
("piano", [])
|
||||
]
|
||||
|
||||
neighbors :: String -> Costs
|
||||
neighbors node = Map.fromList (maybe [] id (Map.lookup node graph))
|
||||
|
||||
closest :: String -> WeightedEdge
|
||||
closest node = head $ sortBy (\x y -> compare (snd x) (snd y)) $ Map.toList $ (neighbors node)
|
||||
|
||||
buildmap graph def initmapfn node = foldl
|
||||
(\accMap key -> Map.insert key def accMap)
|
||||
startingMap
|
||||
keystoadd
|
||||
where startingMap = initmapfn node
|
||||
startKeys = node : (Map.keys startingMap)
|
||||
allKeys = Map.keys graph
|
||||
keystoadd = filter (not . (`elem` startKeys)) allKeys
|
||||
|
||||
initcosts node = buildmap graph inf neighbors node
|
||||
|
||||
initparents node = buildmap graph "" ((Map.map (\x -> node)) . neighbors) node
|
||||
|
||||
safeHead [] = Nothing
|
||||
safeHead (x:xs) = Just x
|
||||
|
||||
cheapest :: [String] -> Costs -> Maybe WeightedEdge
|
||||
cheapest processed costs = safeHead $
|
||||
sortBy (\x y -> compare (snd x) (snd y)) $
|
||||
filter (\(a, b) -> (not . (`elem` processed)) a) $
|
||||
Map.toList $
|
||||
costs
|
||||
|
||||
updatecosts :: Costs -> WeightedEdge -> Costs
|
||||
updatecosts costs (node, cost) = foldl
|
||||
(\acc (neighbor, neighborcost) ->
|
||||
let (Just newcost) = min (neighborcost + cost) <$> (Map.lookup neighbor acc)
|
||||
in Map.insert neighbor newcost acc)
|
||||
costs
|
||||
edges
|
||||
where edges = Map.toList $ neighbors node
|
||||
|
||||
updateparents :: Parents -> Costs -> WeightedEdge -> Parents
|
||||
updateparents parents costs (node, cost) = foldl
|
||||
(\acc (neighbor, neighborcost) -> case (((cost + neighborcost) <) <$> (Map.lookup neighbor costs)) of
|
||||
Just True -> Map.insert neighbor node acc
|
||||
_ -> acc)
|
||||
parents
|
||||
edges
|
||||
where edges = Map.toList $ neighbors node
|
||||
|
||||
shortestpath :: Costs -> Parents -> [String] -> (Costs, Parents)
|
||||
shortestpath costs parents processed = case (cheapest processed costs) of
|
||||
Just (node, cost) -> shortestpath newcosts newparents (node : processed)
|
||||
where newcosts = updatecosts costs (node, cost)
|
||||
newparents = updateparents parents costs (node, cost)
|
||||
Nothing -> (costs, parents)
|
||||
|
||||
costto :: String -> Costs -> Double
|
||||
costto node costMap = case (Map.lookup node costMap) of
|
||||
Just cost -> cost
|
||||
_ -> inf
|
||||
|
||||
pathto :: String -> Parents -> [String]
|
||||
pathto node parentsMap = buildpath node parentsMap [node]
|
||||
where buildpath node parentsMap acc = case (Map.lookup node parentsMap) of
|
||||
Just "book" -> "book" : acc
|
||||
Just parent -> buildpath parent parentsMap (parent : acc)
|
||||
|
||||
costs = initcosts "book"
|
||||
|
||||
parents = initparents "book"
|
||||
|
||||
processed = ["book"]
|
||||
|
||||
main = do
|
||||
(putStrLn . show . (costto "piano")) costsolution
|
||||
(putStrLn . show . (pathto "piano")) parentsolution
|
||||
where (costsolution, parentsolution) = shortestpath costs parents processed
|
||||
80
09_dijkstras_algorithm/PowerShell/01_dijkstras_algorithm.ps1
Normal file
80
09_dijkstras_algorithm/PowerShell/01_dijkstras_algorithm.ps1
Normal file
@@ -0,0 +1,80 @@
|
||||
$infinity = [float]::PositiveInfinity
|
||||
|
||||
# the graph
|
||||
$graph = @{}
|
||||
$graph["start"] = @{}
|
||||
$graph["start"]["a"] = 6
|
||||
$graph["start"]["b"] = 2
|
||||
|
||||
$graph["a"] = @{}
|
||||
$graph["a"]["fin"] = 1
|
||||
|
||||
$graph["b"] = @{}
|
||||
$graph["b"]["a"] = 3
|
||||
$graph["b"]["fin"] = 5
|
||||
|
||||
$graph["fin"] = @{}
|
||||
|
||||
# the costs table
|
||||
$costs = [ordered]@{}
|
||||
$costs["a"] = 6
|
||||
$costs["b"] = 2
|
||||
$costs["fin"] = $infinity
|
||||
|
||||
# the parents table
|
||||
$parents = [ordered]@{}
|
||||
$parents["a"] = "start"
|
||||
$parents["b"] = "start"
|
||||
$parents["fin"] = $null
|
||||
|
||||
$processed = New-Object System.Collections.Generic.HashSet[String]
|
||||
|
||||
function Find-GRKLowestCostNode
|
||||
{
|
||||
param ($costs)
|
||||
$lowest_cost = $infinity
|
||||
$lowest_cost_node = $null
|
||||
# Go through each node.
|
||||
foreach ($node in $costs.GetEnumerator())
|
||||
{
|
||||
$cost = $costs[$node.key]
|
||||
# If it's the lowest cost so far and hasn't been processed yet...
|
||||
if (($cost -lt $lowest_cost) -and ($node.key -notin $processed))
|
||||
{
|
||||
# ... set it as the new lowest-cost node.
|
||||
$lowest_cost = $cost
|
||||
$lowest_cost_node = $node
|
||||
}
|
||||
}
|
||||
return $lowest_cost_node
|
||||
}
|
||||
|
||||
# Find the lowest-cost node that you haven't processed yet.
|
||||
$node = Find-GRKLowestCostNode $costs
|
||||
$i = 0
|
||||
# If you've processed all the nodes, this while loop is done.
|
||||
while ($node -ne $null)
|
||||
{
|
||||
$i++
|
||||
$cost = $costs[$node.Key]
|
||||
$neighbors = $graph[$node.Key]
|
||||
foreach ($n in $neighbors.Keys)
|
||||
{
|
||||
$new_cost = $cost + $neighbors[$n]
|
||||
# If it's cheaper to get to this neighbor by going through this node...
|
||||
if ($costs[$n] -gt $new_cost)
|
||||
{
|
||||
# ... update the cost for this node.
|
||||
$costs[$n] = $new_cost
|
||||
# This node becomes the new parent for this neighbor.
|
||||
$parents[$n] = $node.Key
|
||||
}
|
||||
}
|
||||
# Mark the node as processed.
|
||||
$processed.Add($node.Key) >$null
|
||||
# Find the next node to process, and loop.
|
||||
$node = Find-GRKLowestCostNode $costs
|
||||
}
|
||||
|
||||
Write-Host "Cost from the start to each node:"
|
||||
Write-Host ($costs | Out-String)
|
||||
82
09_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp
Normal file
82
09_dijkstras_algorithm/c++11/01_dijkstras_algorithm.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
using node_t = std::string;
|
||||
using node_cost_t = std::unordered_map<node_t, unsigned>;
|
||||
using graph_t = std::unordered_map<node_t, node_cost_t>;
|
||||
using parent_graph_t = std::unordered_map<node_t, node_t>;
|
||||
|
||||
// Setup graph
|
||||
graph_t graph;
|
||||
graph.reserve(4U);
|
||||
graph.emplace("start", node_cost_t{{"a", 6}, {"b", 2}});
|
||||
graph.emplace("a", node_cost_t{{"finish", 1}});
|
||||
graph.emplace("b", node_cost_t{{"a", 3},{"finish", 5}});
|
||||
graph.emplace("finish", node_cost_t{});
|
||||
// Setup costs table
|
||||
node_cost_t costs{{"a", 6},{"b", 2},{"finish", std::numeric_limits<unsigned>::max()}};
|
||||
// Setup parents table
|
||||
parent_graph_t parents{{"a", "start"}, {"b", "start"}};
|
||||
|
||||
// A vector of processed nodes
|
||||
std::vector<node_t> processed;
|
||||
processed.reserve(3U);
|
||||
// A lambda function to find the lowest cost node
|
||||
const auto find_lowest_cost_node = [&processed](const node_cost_t& costs)
|
||||
{
|
||||
auto lowest_cost = std::numeric_limits<unsigned>::max();
|
||||
node_t lowest_cost_node{};
|
||||
// Go through each node in the costs graph
|
||||
for (const auto& nodeCost : costs)
|
||||
{
|
||||
const auto& cost = nodeCost.second;
|
||||
const auto& node = nodeCost.first;
|
||||
// Check if this node is processed or not;
|
||||
bool isNotProcessed = std::find(processed.cbegin(), processed.cend(), node) == processed.cend();
|
||||
// Find the lowest cost node
|
||||
if (cost < lowest_cost && isNotProcessed)
|
||||
{
|
||||
lowest_cost = cost;
|
||||
lowest_cost_node = node;
|
||||
}
|
||||
}
|
||||
return lowest_cost_node;
|
||||
};
|
||||
|
||||
// node is "b" at this time
|
||||
auto node = find_lowest_cost_node(costs);
|
||||
while (!node.empty())
|
||||
{
|
||||
const auto costSoFar = costs[node];
|
||||
const auto& neighbours = graph[node];
|
||||
// Loop through all the nodes
|
||||
for (const auto& neighbour : neighbours)
|
||||
{
|
||||
const auto newCost = costSoFar + neighbour.second;
|
||||
const auto& currentNeighbourName = neighbour.first;
|
||||
// If it is cheaper than the cost registered in the costs graph, update the costs graph
|
||||
if (newCost < costs[currentNeighbourName])
|
||||
{
|
||||
costs[currentNeighbourName] = newCost;
|
||||
parents[currentNeighbourName] = node;
|
||||
}
|
||||
}
|
||||
// Mark the current node as processed
|
||||
processed.push_back(node);
|
||||
// Find the next node to process. If they are all processed, this will return an empty string.
|
||||
node = find_lowest_cost_node(costs);
|
||||
}
|
||||
std::cout << "Cost from the start to each node:" << std::endl;
|
||||
// prints finish 6 b 2 a 5
|
||||
for (const auto& cost : costs)
|
||||
{
|
||||
std::cout << cost.first << " " << cost.second << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
2
09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.gitignore
vendored
Normal file
2
09_dijkstras_algorithm/csharp/01_dijkstras_algorithm/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
**/bin/*
|
||||
**/obj/*
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ConsoleApplication
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
private const double _infinity = double.PositiveInfinity;
|
||||
private static Dictionary<string, Dictionary<string, double>> _graph = new Dictionary<string, Dictionary<string, double>>();
|
||||
private static List<string> _processed = new List<string>();
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
_graph.Add("start", new Dictionary<string, double>());
|
||||
_graph["start"].Add("a", 6.0);
|
||||
_graph["start"].Add("b", 2.0);
|
||||
|
||||
_graph.Add("a", new Dictionary<string, double>());
|
||||
_graph["a"].Add("fin", 1.0);
|
||||
|
||||
_graph.Add("b", new Dictionary<string, double>());
|
||||
_graph["b"].Add("a", 3.0);
|
||||
_graph["b"].Add("fin", 5.0);
|
||||
|
||||
_graph.Add("fin", new Dictionary<string, double>());
|
||||
|
||||
var costs = new Dictionary<string, double>();
|
||||
costs.Add("a", 6.0);
|
||||
costs.Add("b", 2.0);
|
||||
costs.Add("fin", _infinity);
|
||||
|
||||
var parents = new Dictionary<string, string>();
|
||||
parents.Add("a", "start");
|
||||
parents.Add("b", "start");
|
||||
parents.Add("fin", null);
|
||||
|
||||
var node = FindLowestCostNode(costs);
|
||||
while (node != null)
|
||||
{
|
||||
var cost = costs[node];
|
||||
var neighbors = _graph[node];
|
||||
foreach (var n in neighbors.Keys)
|
||||
{
|
||||
var new_cost = cost + neighbors[n];
|
||||
if (costs[n] > new_cost)
|
||||
{
|
||||
costs[n] = new_cost;
|
||||
parents[n] = node;
|
||||
}
|
||||
}
|
||||
_processed.Add(node);
|
||||
node = FindLowestCostNode(costs);
|
||||
}
|
||||
Console.WriteLine(string.Join(", ", costs));
|
||||
}
|
||||
|
||||
private static string FindLowestCostNode(Dictionary<string, double> costs)
|
||||
{
|
||||
var lowestCost = double.PositiveInfinity;
|
||||
string lowestCostNode = null;
|
||||
foreach (var node in costs)
|
||||
{
|
||||
var cost = node.Value;
|
||||
if (cost < lowestCost && !_processed.Contains(node.Key))
|
||||
{
|
||||
lowestCost = cost;
|
||||
lowestCostNode = node.Key;
|
||||
}
|
||||
}
|
||||
return lowestCostNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": "1.0.0-*",
|
||||
"buildOptions": {
|
||||
"debugType": "portable",
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
"dependencies": {},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.1"
|
||||
}
|
||||
},
|
||||
"imports": "dnxcore50"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
72
09_dijkstras_algorithm/dart/01_djikstra_algorithm.dart
Normal file
72
09_dijkstras_algorithm/dart/01_djikstra_algorithm.dart
Normal file
@@ -0,0 +1,72 @@
|
||||
void main(List<String> args) {
|
||||
final graph = <String, Map<String, double>>{}..addAll(
|
||||
{
|
||||
'start': {
|
||||
'a': 6,
|
||||
'b': 2,
|
||||
},
|
||||
'a': {
|
||||
'end': 1,
|
||||
},
|
||||
'b': {
|
||||
'a': 3,
|
||||
'end': 5,
|
||||
},
|
||||
'end': {},
|
||||
},
|
||||
);
|
||||
|
||||
final costs = <String, double>{
|
||||
'a': 6,
|
||||
'b': 2,
|
||||
'end': double.infinity,
|
||||
};
|
||||
|
||||
final parents = <String, String?>{
|
||||
'a': 'start',
|
||||
'b': 'start',
|
||||
'end': null,
|
||||
};
|
||||
|
||||
djikstra(graph, costs, parents);
|
||||
print(graph);
|
||||
print(costs);
|
||||
print(parents);
|
||||
}
|
||||
|
||||
void djikstra(
|
||||
Map<String, Map<String, double>> graph,
|
||||
Map<String, double> costs,
|
||||
Map<String, String?> parents,
|
||||
) {
|
||||
final processeds = <String>[];
|
||||
String? node = findTheCheapestOne(costs, processeds);
|
||||
|
||||
while (node != null) {
|
||||
final cost = costs[node];
|
||||
final neighbors = graph[node];
|
||||
for (String neighbor in neighbors!.keys) {
|
||||
final double newCost = cost! + neighbors[neighbor]!;
|
||||
if (costs[neighbor]! > newCost) {
|
||||
costs[neighbor] = newCost;
|
||||
parents[neighbor] = node;
|
||||
}
|
||||
}
|
||||
processeds.add(node);
|
||||
node = findTheCheapestOne(costs, processeds);
|
||||
}
|
||||
}
|
||||
|
||||
String? findTheCheapestOne(Map<String, double> costs, List<String> processed) {
|
||||
double cheapestCost = double.infinity;
|
||||
String? cheapestNode;
|
||||
|
||||
for (String node in costs.keys) {
|
||||
final double cost = costs[node]!;
|
||||
if (cost < cheapestCost && !processed.contains(node)) {
|
||||
cheapestCost = cost;
|
||||
cheapestNode = node;
|
||||
}
|
||||
}
|
||||
return cheapestNode;
|
||||
}
|
||||
84
09_dijkstras_algorithm/elixir/01_dijkstras_algorithm.exs
Normal file
84
09_dijkstras_algorithm/elixir/01_dijkstras_algorithm.exs
Normal file
@@ -0,0 +1,84 @@
|
||||
defmodule DijkstrasAlgorithm do
|
||||
def find_shortest_path(graph, costs, parents),
|
||||
do: do_find_shortest_path(graph, costs, parents, [])
|
||||
|
||||
defp do_find_shortest_path(graph, costs, parents, processed) do
|
||||
find_lowest_cost_node(costs, processed)
|
||||
|> process_node(processed, graph, costs, parents)
|
||||
end
|
||||
|
||||
defp process_node(nil, _, _, costs, parents), do: {costs, parents}
|
||||
|
||||
defp process_node(node, processed, graph, costs, parents) do
|
||||
node_cost = costs[node]
|
||||
neighbors = for(neighbor_node_cost <- graph[node], do: neighbor_node_cost)
|
||||
|
||||
{new_costs, new_parents} = process_node_neighbors(node, node_cost, neighbors, costs, parents)
|
||||
|
||||
do_find_shortest_path(graph, new_costs, new_parents, [node | processed])
|
||||
end
|
||||
|
||||
defp process_node_neighbors(node, node_cost, neighbors, costs, parents)
|
||||
|
||||
defp process_node_neighbors(_, _, [], costs, parents), do: {costs, parents}
|
||||
|
||||
defp process_node_neighbors(node, node_cost, [neighbor | tail], costs, parents) do
|
||||
{neighbor_node, neighbor_cost} = neighbor
|
||||
new_cost = node_cost + neighbor_cost
|
||||
|
||||
if costs[neighbor_node] > node_cost + neighbor_cost do
|
||||
new_costs = %{costs | neighbor_node => new_cost}
|
||||
new_parents = %{parents | neighbor_node => node}
|
||||
|
||||
process_node_neighbors(node, node_cost, tail, new_costs, new_parents)
|
||||
else
|
||||
process_node_neighbors(node, node_cost, tail, costs, parents)
|
||||
end
|
||||
end
|
||||
|
||||
defp find_lowest_cost_node(costs, processed) do
|
||||
{lowest_cost_node, _} =
|
||||
for({node, cost} <- costs, node not in processed, do: {node, cost})
|
||||
|> find_lowest_cost
|
||||
|
||||
lowest_cost_node
|
||||
end
|
||||
|
||||
defp find_lowest_cost([]), do: {nil, :infinity}
|
||||
|
||||
defp find_lowest_cost([node_cost | []]), do: node_cost
|
||||
|
||||
defp find_lowest_cost([node_cost = {_, cost} | tail]) do
|
||||
(min_node_cost = {_, min_cost}) = find_lowest_cost(tail)
|
||||
|
||||
if cost < min_cost,
|
||||
do: node_cost,
|
||||
else: min_node_cost
|
||||
end
|
||||
end
|
||||
|
||||
# the graph
|
||||
graph = %{
|
||||
"start" => %{"a" => 6, "b" => 2},
|
||||
"a" => %{"fin" => 1},
|
||||
"b" => %{"a" => 3, "fin" => 5},
|
||||
"fin" => %{}
|
||||
}
|
||||
|
||||
# the costs table
|
||||
costs = %{
|
||||
"a" => 6,
|
||||
"b" => 2,
|
||||
"fin" => :infinity
|
||||
}
|
||||
|
||||
# the parents table
|
||||
parents = %{
|
||||
"a" => "start",
|
||||
"b" => "start",
|
||||
"fin" => nil
|
||||
}
|
||||
|
||||
{costs, _} = DijkstrasAlgorithm.find_shortest_path(graph, costs, parents)
|
||||
IO.puts("Cost from the start to each node:")
|
||||
IO.inspect(costs)
|
||||
@@ -0,0 +1,82 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DijkstrasAlgorithm {
|
||||
// the graph
|
||||
private static Map<String, Map<String, Double>> graph = new HashMap<>();
|
||||
private static List<String> processed = new ArrayList<>();
|
||||
|
||||
private static String findLowestCostNode(Map<String, Double> costs) {
|
||||
Double lowestCost = Double.POSITIVE_INFINITY;
|
||||
String lowestCostNode = null;
|
||||
|
||||
// Go through each node
|
||||
for (Map.Entry<String, Double> node : costs.entrySet()) {
|
||||
Double cost = node.getValue();
|
||||
// If it's the lowest cost so far and hasn't been processed yet...
|
||||
if (cost < lowestCost && !processed.contains(node.getKey())) {
|
||||
// ... set it as the new lowest-cost node.
|
||||
lowestCost = cost;
|
||||
lowestCostNode = node.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
return lowestCostNode;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
graph.put("start", new HashMap<>());
|
||||
graph.get("start").put("a", 6.0);
|
||||
graph.get("start").put("b", 2.0);
|
||||
|
||||
graph.put("a", new HashMap<>());
|
||||
graph.get("a").put("fin", 1.0);
|
||||
|
||||
graph.put("b", new HashMap<>());
|
||||
graph.get("b").put("a", 3.0);
|
||||
graph.get("b").put("fin", 5.0);
|
||||
|
||||
graph.put("fin", new HashMap<>());
|
||||
|
||||
// The costs table
|
||||
Map<String, Double> costs = new HashMap<>();
|
||||
costs.put("a", 6.0);
|
||||
costs.put("b", 2.0);
|
||||
costs.put("fin", Double.POSITIVE_INFINITY);
|
||||
|
||||
// the parents table
|
||||
Map<String, String> parents = new HashMap<>();
|
||||
parents.put("a", "start");
|
||||
parents.put("b", "start");
|
||||
parents.put("fin", null);
|
||||
|
||||
String node = findLowestCostNode(costs);
|
||||
while (node != null) {
|
||||
Double cost = costs.get(node);
|
||||
// Go through all the neighbors of this node
|
||||
|
||||
Map<String, Double> neighbors = graph.get(node);
|
||||
|
||||
for (String n : neighbors.keySet()) {
|
||||
double newCost = cost + neighbors.get(n);
|
||||
// If it's cheaper to get to this neighbor by going through this node
|
||||
if (costs.get(n) > newCost) {
|
||||
// ... update the cost for this node
|
||||
costs.put(n, newCost);
|
||||
// This node becomes the new parent for this neighbor.
|
||||
parents.put(n, node);
|
||||
}
|
||||
}
|
||||
// Mark the node as processed
|
||||
processed.add(node);
|
||||
|
||||
// Find the next node to process, and loop
|
||||
node = findLowestCostNode(costs);
|
||||
}
|
||||
|
||||
System.out.println("Cost from the start to each node:");
|
||||
System.out.println(costs); // { a: 5, b: 2, fin: 6 }
|
||||
}
|
||||
}
|
||||
79
09_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js
Normal file
79
09_dijkstras_algorithm/javascript/01_dijkstras_algorithm.js
Normal file
@@ -0,0 +1,79 @@
|
||||
"use strict";
|
||||
|
||||
// the graph
|
||||
const graph = {};
|
||||
graph["start"] = {};
|
||||
graph["start"]["a"] = 6;
|
||||
graph["start"]["b"] = 2;
|
||||
|
||||
graph["a"] = {};
|
||||
graph["a"]["fin"] = 1;
|
||||
|
||||
graph["b"] = {};
|
||||
graph["b"]["a"] = 3;
|
||||
graph["b"]["fin"] = 5;
|
||||
|
||||
graph["fin"] = {};
|
||||
|
||||
// The costs table
|
||||
const costs = {};
|
||||
costs["a"] = 6;
|
||||
costs["b"] = 2;
|
||||
costs["fin"] = Infinity;
|
||||
|
||||
// the parents table
|
||||
const parents = {};
|
||||
parents["a"] = "start";
|
||||
parents["b"] = "start";
|
||||
parents["fin"] = null;
|
||||
|
||||
let processed = [];
|
||||
|
||||
/**
|
||||
* Find the lowest node
|
||||
* @param {Object} itCosts Hash table
|
||||
* @returns {(string|null)} The lowest node
|
||||
*/
|
||||
function findLowestCostNode(costs) {
|
||||
let lowestCost = Infinity;
|
||||
let lowestCostNode = null;
|
||||
|
||||
// Go through each node
|
||||
for (let node in costs) {
|
||||
const cost = costs[node];
|
||||
// If it's the lowest cost so far and hasn't been processed yet...
|
||||
if (cost < lowestCost && processed.indexOf(node) === -1) {
|
||||
// ... set it as the new lowest-cost node.
|
||||
lowestCost = cost;
|
||||
lowestCostNode = node;
|
||||
}
|
||||
}
|
||||
return lowestCostNode;
|
||||
}
|
||||
|
||||
let node = findLowestCostNode(costs);
|
||||
|
||||
while (node !== null) {
|
||||
const cost = costs[node];
|
||||
// Go through all the neighbors of this node
|
||||
const neighbors = graph[node];
|
||||
Object.keys(neighbors).forEach(function(n) {
|
||||
const new_cost = cost + neighbors[n];
|
||||
// If it's cheaper to get to this neighbor by going through this node
|
||||
if (costs[n] > new_cost) {
|
||||
// ... update the cost for this node
|
||||
costs[n] = new_cost;
|
||||
// This node becomes the new parent for this neighbor.
|
||||
parents[n] = node;
|
||||
}
|
||||
});
|
||||
|
||||
// Mark the node as processed
|
||||
processed = processed.concat(node);
|
||||
|
||||
// Find the next node to process, and loop
|
||||
node = findLowestCostNode(costs);
|
||||
}
|
||||
|
||||
console.log("Cost from the start to each node:");
|
||||
console.log(costs); // { a: 5, b: 2, fin: 6 }
|
||||
64
09_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl
Normal file
64
09_dijkstras_algorithm/julia/01_dijkstras_algorithm.jl
Normal file
@@ -0,0 +1,64 @@
|
||||
# Julia version: LTS (v1.0.3)
|
||||
using Test
|
||||
|
||||
graph = Dict()
|
||||
graph["start"] = Dict()
|
||||
graph["start"]["a"] = 6
|
||||
graph["start"]["b"] = 2
|
||||
|
||||
graph["a"] = Dict()
|
||||
graph["a"]["fin"] = 1
|
||||
|
||||
graph["b"] = Dict()
|
||||
graph["b"]["a"] = 3
|
||||
graph["b"]["fin"] = 5
|
||||
|
||||
graph["fin"] = Dict()
|
||||
|
||||
# the costs table
|
||||
infinity = Inf
|
||||
costs = Dict()
|
||||
costs["a"] = 6
|
||||
costs["b"] = 2
|
||||
costs["fin"] = infinity
|
||||
|
||||
# the parents table
|
||||
parents = Dict()
|
||||
parents["a"] = "start"
|
||||
parents["b"] = "start"
|
||||
parents["fin"] = nothing
|
||||
|
||||
processed = []
|
||||
|
||||
function find_lowest_cost_node(costs)
|
||||
lowest_cost = Inf
|
||||
lowest_cost_node = nothing
|
||||
for node in keys(costs)
|
||||
cost = costs[node]
|
||||
if cost < lowest_cost && node ∉ processed
|
||||
lowest_cost = cost
|
||||
lowest_cost_node = node
|
||||
end
|
||||
end
|
||||
return lowest_cost_node
|
||||
end
|
||||
|
||||
node = find_lowest_cost_node(costs)
|
||||
while node != nothing
|
||||
global node
|
||||
cost = costs[node]
|
||||
neighbors = graph[node]
|
||||
for n in keys(neighbors)
|
||||
new_cost = cost + neighbors[n]
|
||||
if costs[n] > new_cost
|
||||
costs[n] = new_cost
|
||||
parents[n] = node
|
||||
end
|
||||
end
|
||||
push!(processed,node)
|
||||
node = find_lowest_cost_node(costs)
|
||||
end
|
||||
|
||||
println("Cost from the start to each node:")
|
||||
println(costs)
|
||||
@test costs == Dict("fin"=>6,"b"=>2,"a"=>5)
|
||||
72
09_dijkstras_algorithm/lua/01_dijkstras_algorithm.lua
Normal file
72
09_dijkstras_algorithm/lua/01_dijkstras_algorithm.lua
Normal file
@@ -0,0 +1,72 @@
|
||||
-- the graph
|
||||
local graph = {}
|
||||
graph["start"] = {}
|
||||
graph["start"]["a"] = 6
|
||||
graph["start"]["b"] = 2
|
||||
|
||||
graph["a"] = {}
|
||||
graph["a"]["fin"] = 1
|
||||
|
||||
graph["b"] = {}
|
||||
graph["b"]["a"] = 3
|
||||
graph["b"]["fin"] = 5
|
||||
|
||||
graph["fin"] = {}
|
||||
|
||||
-- the costs table
|
||||
local infinity = math.huge
|
||||
local costs = {}
|
||||
costs["a"] = 6
|
||||
costs["b"] = 2
|
||||
costs["fin"] = infinity
|
||||
|
||||
-- the parents table
|
||||
local parents = {}
|
||||
parents["a"] = "start"
|
||||
parents["b"] = "start"
|
||||
parents["fin"] = nil
|
||||
|
||||
local processed = {}
|
||||
|
||||
local function find_lowest_cost_node(costs)
|
||||
local lowest_cost = math.huge
|
||||
local lowest_cost_node = nil
|
||||
-- Go through each node.
|
||||
for node, cost in pairs(costs) do
|
||||
-- If it's the lowest cost so far and hasn't been processed yet...
|
||||
if cost < lowest_cost and not processed[node] then
|
||||
-- ... set it as the new lowest-cost node.
|
||||
lowest_cost = cost
|
||||
lowest_cost_node = node
|
||||
end
|
||||
end
|
||||
return lowest_cost_node
|
||||
end
|
||||
|
||||
-- Find the lowest-cost node that you haven't processed yet.
|
||||
local node = find_lowest_cost_node(costs)
|
||||
-- If you've processed all the nodes, this while loop is done.
|
||||
while node ~= nil do
|
||||
local cost = costs[node]
|
||||
-- Go through all the neighbors of this node.
|
||||
local neighbors = graph[node]
|
||||
for n, n_cost in pairs(neighbors) do
|
||||
local new_cost = cost + n_cost
|
||||
-- If it's cheaper to get to this neighbor by going through this node...
|
||||
if costs[n] > new_cost then
|
||||
-- ... update the cost for this node.
|
||||
costs[n] = new_cost
|
||||
-- This node becomes the new parent for this neighbor.
|
||||
parents[n] = node
|
||||
end
|
||||
end
|
||||
-- Mark the node as processed.
|
||||
processed[node] = true
|
||||
-- Find the next node to process, and loop.
|
||||
node = find_lowest_cost_node(costs)
|
||||
end
|
||||
|
||||
print("Cost from the start to each node:")
|
||||
for key, value in pairs(costs) do
|
||||
print(key .. ": " .. value)
|
||||
end
|
||||
73
09_dijkstras_algorithm/php/01_dijkstras_algorithm.php
Normal file
73
09_dijkstras_algorithm/php/01_dijkstras_algorithm.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
$graph = [];
|
||||
$graph["start"] = [];
|
||||
$graph["start"]["a"] = 6;
|
||||
$graph["start"]["b"] = 2;
|
||||
|
||||
$graph["a"] = [];
|
||||
$graph["a"]["fin"] = 1;
|
||||
|
||||
$graph["b"] = [];
|
||||
$graph["b"]["a"] = 3;
|
||||
$graph["b"]["fin"] = 5;
|
||||
|
||||
$graph["fin"] = [];
|
||||
|
||||
# the costs table
|
||||
$infinity = PHP_INT_MAX;
|
||||
$costs = [];
|
||||
$costs["a"] = 6;
|
||||
$costs["b"] = 2;
|
||||
$costs["fin"] = $infinity;
|
||||
|
||||
# the parents table
|
||||
$parents = [];
|
||||
$parents["a"] = "start";
|
||||
$parents["b"] = "start";
|
||||
$parents["fin"] = null;
|
||||
|
||||
$processed = [];
|
||||
|
||||
function findLowestCodeNode(array $costs) {
|
||||
$lowestCost = PHP_INT_MAX;
|
||||
$lowestCostNode = null;
|
||||
global $processed;
|
||||
# Go through each node.
|
||||
foreach ($costs as $node => $cost) {
|
||||
# If it's the lowest cost so far and hasn't been processed yet...
|
||||
if ($cost < $lowestCost && !array_key_exists($node, $processed)) {
|
||||
# ... set it as the new lowest-cost node.
|
||||
$lowestCost = $cost;
|
||||
$lowestCostNode = $node;
|
||||
}
|
||||
}
|
||||
|
||||
return $lowestCostNode;
|
||||
}
|
||||
|
||||
# Find the lowest-cost node that you haven't processed yet.
|
||||
$node = findLowestCodeNode($costs);
|
||||
|
||||
# If you've processed all the nodes, this while loop is done.
|
||||
while ($node) {
|
||||
$cost = $costs[$node];
|
||||
# Go through all the neighbors of this node.
|
||||
$neighbors = $graph[$node];
|
||||
foreach (array_keys($neighbors) as $n) {
|
||||
$newCost = $cost + $neighbors[$n];
|
||||
# If it's cheaper to get to this neighbor by going through this node...
|
||||
if ($costs[$n] > $newCost) {
|
||||
# ... update the cost for this node.
|
||||
$costs[$n] = $newCost;
|
||||
# This node becomes the new parent for this neighbor.
|
||||
$parents[$n] = $node;
|
||||
}
|
||||
}
|
||||
# Mark the node as processed.
|
||||
$processed[$node] = true;
|
||||
# Find the next node to process, and loop.
|
||||
$node = findLowestCodeNode($costs);
|
||||
}
|
||||
|
||||
print("Cost from the start to each node:");
|
||||
var_dump($costs);
|
||||
66
09_dijkstras_algorithm/python/01_dijkstras_algorithm.py
Normal file
66
09_dijkstras_algorithm/python/01_dijkstras_algorithm.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# the graph
|
||||
graph = {}
|
||||
graph["start"] = {}
|
||||
graph["start"]["a"] = 6
|
||||
graph["start"]["b"] = 2
|
||||
|
||||
graph["a"] = {}
|
||||
graph["a"]["fin"] = 1
|
||||
|
||||
graph["b"] = {}
|
||||
graph["b"]["a"] = 3
|
||||
graph["b"]["fin"] = 5
|
||||
|
||||
graph["fin"] = {}
|
||||
|
||||
# the costs table
|
||||
infinity = float("inf")
|
||||
costs = {}
|
||||
costs["a"] = 6
|
||||
costs["b"] = 2
|
||||
costs["fin"] = infinity
|
||||
|
||||
# the parents table
|
||||
parents = {}
|
||||
parents["a"] = "start"
|
||||
parents["b"] = "start"
|
||||
parents["fin"] = None
|
||||
|
||||
processed = []
|
||||
|
||||
def find_lowest_cost_node(costs):
|
||||
lowest_cost = float("inf")
|
||||
lowest_cost_node = None
|
||||
# Go through each node.
|
||||
for node in costs:
|
||||
cost = costs[node]
|
||||
# If it's the lowest cost so far and hasn't been processed yet...
|
||||
if cost < lowest_cost and node not in processed:
|
||||
# ... set it as the new lowest-cost node.
|
||||
lowest_cost = cost
|
||||
lowest_cost_node = node
|
||||
return lowest_cost_node
|
||||
|
||||
# Find the lowest-cost node that you haven't processed yet.
|
||||
node = find_lowest_cost_node(costs)
|
||||
# If you've processed all the nodes, this while loop is done.
|
||||
while node is not None:
|
||||
cost = costs[node]
|
||||
# Go through all the neighbors of this node.
|
||||
neighbors = graph[node]
|
||||
for n in neighbors.keys():
|
||||
new_cost = cost + neighbors[n]
|
||||
# If it's cheaper to get to this neighbor by going through this node...
|
||||
if costs[n] > new_cost:
|
||||
# ... update the cost for this node.
|
||||
costs[n] = new_cost
|
||||
# This node becomes the new parent for this neighbor.
|
||||
parents[n] = node
|
||||
# Mark the node as processed.
|
||||
processed.append(node)
|
||||
# Find the next node to process, and loop.
|
||||
node = find_lowest_cost_node(costs)
|
||||
|
||||
print("Cost from the start to each node:")
|
||||
print(costs)
|
||||
|
||||
69
09_dijkstras_algorithm/ruby/01_dijkstras_algorithm.rb
Normal file
69
09_dijkstras_algorithm/ruby/01_dijkstras_algorithm.rb
Normal file
@@ -0,0 +1,69 @@
|
||||
# the graph
|
||||
graph = {}
|
||||
graph["start"] = {}
|
||||
graph["start"]["a"] = 6
|
||||
graph["start"]["b"] = 2
|
||||
|
||||
graph["a"] = {}
|
||||
graph["a"]["fin"] = 1
|
||||
|
||||
graph["b"] = {}
|
||||
graph["b"]["a"] = 3
|
||||
graph["b"]["fin"] = 5
|
||||
|
||||
graph["fin"] = {}
|
||||
|
||||
# the costs table
|
||||
costs = {}
|
||||
costs["a"] = 6
|
||||
costs["b"] = 2
|
||||
costs["fin"] = Float::INFINITY
|
||||
|
||||
# the parents table
|
||||
parents = {}
|
||||
parents["a"] = "start"
|
||||
parents["b"] = "start"
|
||||
parents["fin"] = nil
|
||||
|
||||
@processed = []
|
||||
|
||||
def find_lowest_cost_node(costs)
|
||||
lowest_cost = Float::INFINITY
|
||||
lowest_cost_node = nil
|
||||
# Go through each node.
|
||||
costs.each do |node, cost|
|
||||
# If it's the lowest cost so far and hasn't been processed yet...
|
||||
if cost < lowest_cost && !@processed.member?(node)
|
||||
# ... set it as the new lowest-cost node.
|
||||
lowest_cost = cost
|
||||
lowest_cost_node = node
|
||||
end
|
||||
end
|
||||
lowest_cost_node
|
||||
end
|
||||
|
||||
# Find the lowest-cost node that you haven't processed yet.
|
||||
node = find_lowest_cost_node(costs)
|
||||
# If you've processed all the nodes, this while loop is done.
|
||||
until node.nil?
|
||||
cost = costs[node]
|
||||
# Go through all the neighbors of this node.
|
||||
neighbors = graph[node]
|
||||
neighbors.keys.each do |n|
|
||||
new_cost = cost + neighbors[n]
|
||||
# If it's cheaper to get to this neighbor by going through this node...
|
||||
if costs[n] > new_cost
|
||||
# ... update the cost for this node.
|
||||
costs[n] = new_cost
|
||||
# This node becomes the new parent for this neighbor.
|
||||
parents[n] = node
|
||||
end
|
||||
end
|
||||
# Mark the node as processed.
|
||||
@processed << node
|
||||
# Find the next node to process, and loop.
|
||||
node = find_lowest_cost_node(costs)
|
||||
end
|
||||
|
||||
puts "Cost from the start to each node:"
|
||||
puts costs
|
||||
79
09_dijkstras_algorithm/swift/01_dijkstras_algorithm.swift
Normal file
79
09_dijkstras_algorithm/swift/01_dijkstras_algorithm.swift
Normal file
@@ -0,0 +1,79 @@
|
||||
import Foundation
|
||||
|
||||
// the graph
|
||||
var graph = [String : [String: Double]] ()
|
||||
graph["start"] = [String: Double]()
|
||||
graph["start"]?["a"] = 6
|
||||
graph["start"]?["b"] = 2
|
||||
|
||||
graph["a"] = [String: Double]()
|
||||
graph["a"]?["fin"] = 1
|
||||
|
||||
graph["b"] = [String: Double]()
|
||||
graph["b"]?["a"] = 3
|
||||
graph["b"]?["fin"] = 5
|
||||
|
||||
graph["fin"] = [String: Double]()
|
||||
|
||||
// the costs table
|
||||
let infinity = Double.infinity
|
||||
var costs = [String: Double]()
|
||||
costs["a"] = 6
|
||||
costs["b"] = 2
|
||||
costs["fin"] = infinity
|
||||
|
||||
// the parents table
|
||||
var parents = [String: String]()
|
||||
parents["a"] = "start"
|
||||
parents["b"] = "start"
|
||||
parents["fin"] = nil
|
||||
|
||||
var processed = [String]()
|
||||
|
||||
func findLowestCostNode(costs: [String: Double]) -> [String: Double] {
|
||||
var lowestCost = Double.infinity
|
||||
var lowestCostNode = [String: Double]()
|
||||
// Go through each node.
|
||||
for node in costs {
|
||||
let cost = node.value
|
||||
// If it's the lowest cost so far and hasn't been processed yet...
|
||||
if (cost < lowestCost) && !processed.contains(node.key) {
|
||||
// ... set it as the new lowest-cost node.
|
||||
lowestCost = cost
|
||||
lowestCostNode = [node.key : node.value]
|
||||
}
|
||||
|
||||
}
|
||||
return lowestCostNode
|
||||
}
|
||||
|
||||
// Find the lowest-cost node that you haven't processed yet.
|
||||
var node = findLowestCostNode(costs: costs)
|
||||
|
||||
// If you've processed all the nodes, this while loop is done.
|
||||
while !node.isEmpty {
|
||||
// Swift Note: Unfortunately there are some limits for working with Dictionary inside Dictionary, so we have to use temp "nodeFirstKey" variable as workaround
|
||||
var nodeFirstKey = node.first?.key
|
||||
var cost = costs[nodeFirstKey!]
|
||||
// Go through all the neighbors of this node.
|
||||
var neighbors = graph[nodeFirstKey!]
|
||||
for n in (neighbors?.keys)! {
|
||||
var newCost = cost! + (neighbors?[n])!
|
||||
// If it's cheaper to get to this neighbor by going through this node...
|
||||
if costs[n]! > newCost {
|
||||
// ... update the cost for this node.
|
||||
costs[n] = newCost
|
||||
// This node becomes the new parent for this neighbor.
|
||||
parents[n] = nodeFirstKey
|
||||
}
|
||||
}
|
||||
// Mark the node as processed.
|
||||
processed.append(nodeFirstKey!)
|
||||
// Find the next node to process, and loop.
|
||||
node = findLowestCostNode(costs: costs)
|
||||
}
|
||||
|
||||
|
||||
print("Cost from the start to each node:")
|
||||
print(costs) // -> ["b": 2.0, "fin": 6.0, "a": 5.0]
|
||||
|
||||
161
09_dijkstras_algorithm/zig/dijkstras_algorithm.zig
Normal file
161
09_dijkstras_algorithm/zig/dijkstras_algorithm.zig
Normal file
@@ -0,0 +1,161 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const heap = std.heap;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer arena.deinit();
|
||||
|
||||
var graph = std.StringHashMap(*std.StringHashMap(f32)).init(arena.allocator());
|
||||
|
||||
var start = std.StringHashMap(f32).init(arena.allocator());
|
||||
try start.put("a", 6);
|
||||
try start.put("b", 2);
|
||||
try graph.put("start", &start);
|
||||
|
||||
var a = std.StringHashMap(f32).init(arena.allocator());
|
||||
try a.put("finish", 1);
|
||||
try graph.put("a", &a);
|
||||
|
||||
var b = std.StringHashMap(f32).init(arena.allocator());
|
||||
try b.put("a", 3);
|
||||
try b.put("finish", 5);
|
||||
try graph.put("b", &b);
|
||||
|
||||
var fin = std.StringHashMap(f32).init(arena.allocator());
|
||||
try graph.put("finish", &fin);
|
||||
|
||||
var result = try dijkstra(arena.allocator(), &graph, "start", "finish");
|
||||
|
||||
std.debug.print("Cost from the start to each node:\n", .{});
|
||||
var costs_it = result.costs.iterator();
|
||||
while (costs_it.next()) |cost| {
|
||||
std.debug.print("{s}: {d} ", .{ cost.key_ptr.*, cost.value_ptr.* });
|
||||
}
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print("\n", .{});
|
||||
std.debug.print("Path from start to finish:\n", .{});
|
||||
var path_it = result.path.iterator();
|
||||
while (path_it.next()) |parent| {
|
||||
std.debug.print("{s} = {?s}\n", .{ parent.key_ptr.*, parent.value_ptr.* });
|
||||
}
|
||||
}
|
||||
|
||||
/// this struct is needed because coercing an anonymous struct literal to an
|
||||
/// error union is not supported by zig yet. Once this is fixed (with the
|
||||
/// self-hosted compiler, see https://github.com/ziglang/zig/issues/11443), the
|
||||
/// dijkstra function could just return:
|
||||
/// ```zig
|
||||
/// return {
|
||||
/// .costs = costs,
|
||||
/// .path = parents,
|
||||
/// };
|
||||
/// ```
|
||||
const dijkstraResult = struct {
|
||||
costs: std.StringHashMap(f32),
|
||||
path: std.StringHashMap(?[]const u8),
|
||||
};
|
||||
|
||||
/// applies the dijkstra algorithm on the provided graph using
|
||||
/// the provided start anf finish nodes.
|
||||
fn dijkstra(
|
||||
allocator: mem.Allocator,
|
||||
graph: *std.StringHashMap(*std.StringHashMap(f32)),
|
||||
start: []const u8,
|
||||
finish: []const u8,
|
||||
) !dijkstraResult {
|
||||
var costs = std.StringHashMap(f32).init(allocator);
|
||||
var parents = std.StringHashMap(?[]const u8).init(allocator);
|
||||
try costs.put(finish, std.math.inf_f32);
|
||||
try parents.put(finish, null);
|
||||
|
||||
// initialize costs and parents maps for the nodes having start as parent
|
||||
var start_graph = graph.get(start);
|
||||
if (start_graph) |sg| {
|
||||
var it = sg.iterator();
|
||||
while (it.next()) |elem| {
|
||||
try costs.put(elem.key_ptr.*, elem.value_ptr.*);
|
||||
try parents.put(elem.key_ptr.*, start);
|
||||
}
|
||||
}
|
||||
|
||||
var processed = std.BufSet.init(allocator);
|
||||
|
||||
var n = findCheapestNode(&costs, &processed);
|
||||
while (n) |node| : (n = findCheapestNode(&costs, &processed)) {
|
||||
var cost = costs.get(node).?;
|
||||
var neighbors = graph.get(node);
|
||||
if (neighbors) |nbors| {
|
||||
var it = nbors.iterator();
|
||||
while (it.next()) |neighbor| {
|
||||
var new_cost = cost + neighbor.value_ptr.*;
|
||||
if (costs.get(neighbor.key_ptr.*).? > new_cost) {
|
||||
// update maps if we found a cheaper path
|
||||
try costs.put(neighbor.key_ptr.*, new_cost);
|
||||
try parents.put(neighbor.key_ptr.*, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
try processed.insert(node);
|
||||
}
|
||||
|
||||
return dijkstraResult{
|
||||
.costs = costs,
|
||||
.path = parents,
|
||||
};
|
||||
}
|
||||
|
||||
/// finds the cheapest node among the not yet processed ones.
|
||||
fn findCheapestNode(costs: *std.StringHashMap(f32), processed: *std.BufSet) ?[]const u8 {
|
||||
var lowest_cost = std.math.inf_f32;
|
||||
var lowest_cost_node: ?[]const u8 = null;
|
||||
|
||||
var it = costs.iterator();
|
||||
while (it.next()) |node| {
|
||||
if (node.value_ptr.* < lowest_cost and !processed.contains(node.key_ptr.*)) {
|
||||
lowest_cost = node.value_ptr.*;
|
||||
lowest_cost_node = node.key_ptr.*;
|
||||
}
|
||||
}
|
||||
|
||||
return lowest_cost_node;
|
||||
}
|
||||
|
||||
test "dijkstra" {
|
||||
var gpa = heap.GeneralPurposeAllocator(.{}){};
|
||||
var arena = heap.ArenaAllocator.init(gpa.allocator());
|
||||
defer {
|
||||
arena.deinit();
|
||||
const leaked = gpa.deinit();
|
||||
if (leaked) std.testing.expect(false) catch @panic("TEST FAIL"); //fail test; can't try in defer as defer is executed after we return
|
||||
}
|
||||
|
||||
var graph = std.StringHashMap(*std.StringHashMap(f32)).init(arena.allocator());
|
||||
|
||||
var start = std.StringHashMap(f32).init(arena.allocator());
|
||||
try start.put("a", 6);
|
||||
try start.put("b", 2);
|
||||
try graph.put("start", &start);
|
||||
|
||||
var a = std.StringHashMap(f32).init(arena.allocator());
|
||||
try a.put("finish", 1);
|
||||
try graph.put("a", &a);
|
||||
|
||||
var b = std.StringHashMap(f32).init(arena.allocator());
|
||||
try b.put("a", 3);
|
||||
try b.put("finish", 5);
|
||||
try graph.put("b", &b);
|
||||
|
||||
var fin = std.StringHashMap(f32).init(arena.allocator());
|
||||
try graph.put("finish", &fin);
|
||||
|
||||
var result = try dijkstra(arena.allocator(), &graph, "start", "finish");
|
||||
|
||||
try std.testing.expectEqual(result.costs.get("a").?, 5);
|
||||
try std.testing.expectEqual(result.costs.get("b").?, 2);
|
||||
try std.testing.expectEqual(result.costs.get("finish").?, 6);
|
||||
try std.testing.expectEqual(result.path.get("b").?, "start");
|
||||
try std.testing.expectEqual(result.path.get("a").?, "b");
|
||||
try std.testing.expectEqual(result.path.get("finish").?, "a");
|
||||
}
|
||||
Reference in New Issue
Block a user