reorg and add code for second edition

This commit is contained in:
Aditya Bhargava
2023-08-09 08:20:19 -05:00
parent 9306432a1b
commit 933acafaf3
89 changed files with 18 additions and 117 deletions

View 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 }

View 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
}

View 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

View 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)

View 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;
}

View File

@@ -0,0 +1,2 @@
**/bin/*
**/obj/*

View File

@@ -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;
}
}
}

View File

@@ -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

View 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;
}

View 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)

View File

@@ -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 }
}
}

View 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 }

View 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)

View 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

View 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);

View 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)

View 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

View 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]

View 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");
}