feat(dijkstra): working algorithm with array list
Need to make it better and use an actual priority-queue
This commit is contained in:
124
AdventOfCode2023/src/graph/graph.zig
Normal file
124
AdventOfCode2023/src/graph/graph.zig
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const expect = std.testing.expect;
|
||||||
|
const Order = std.math.Order;
|
||||||
|
const print = std.debug.print;
|
||||||
|
const log = std.log;
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
const Edge = struct {
|
||||||
|
in_node: *Node,
|
||||||
|
out_node: *Node,
|
||||||
|
|
||||||
|
distance: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Node = struct {
|
||||||
|
out_edges: []const Edge,
|
||||||
|
|
||||||
|
label: []const u8,
|
||||||
|
work_distance: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Graph = struct {
|
||||||
|
nodes: []*Node,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1 function Dijkstra(Graph, source):
|
||||||
|
// 2
|
||||||
|
// 3 for each vertex v in Graph.Vertices:
|
||||||
|
// 4 dist[v] ← INFINITY
|
||||||
|
// 5 prev[v] ← UNDEFINED
|
||||||
|
// 6 add v to Q
|
||||||
|
// 7 dist[source] ← 0
|
||||||
|
// 8
|
||||||
|
// 9 while Q is not empty:
|
||||||
|
// 10 u ← vertex in Q with minimum dist[u]
|
||||||
|
// 11 remove u from Q
|
||||||
|
// 12
|
||||||
|
// 13 for each neighbor v of u still in Q:
|
||||||
|
// 14 alt ← dist[u] + Graph.Edges(u, v)
|
||||||
|
// 15 if alt < dist[v]:
|
||||||
|
// 16 dist[v] ← alt
|
||||||
|
// 17 prev[v] ← u
|
||||||
|
// 18
|
||||||
|
// 19 return dist[], prev[]
|
||||||
|
|
||||||
|
fn find_shortest_index(list: *std.ArrayList(*const Node)) usize {
|
||||||
|
var shortestIndex: usize = 0;
|
||||||
|
|
||||||
|
for (list.items, 0..) |item, index| {
|
||||||
|
if (item.work_distance < list.items[shortestIndex].work_distance) {
|
||||||
|
shortestIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shortestIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dijkstra(allocator: std.mem.Allocator, graph: Graph, source: *Node, destination: *Node) !usize {
|
||||||
|
var work_map = std.AutoHashMap(*const Node, *const Node).init(allocator);
|
||||||
|
|
||||||
|
// this is for sure the wrong data structure
|
||||||
|
// properly look at 'priority queue'.
|
||||||
|
var work_queue = std.ArrayList(*const Node).init(allocator);
|
||||||
|
|
||||||
|
for (graph.nodes) |node| {
|
||||||
|
node.*.work_distance = 99999999999;
|
||||||
|
try work_queue.append(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
source.work_distance = 0;
|
||||||
|
|
||||||
|
while (work_queue.items.len > 0) {
|
||||||
|
const closest_node_index = find_shortest_index(&work_queue);
|
||||||
|
const closest_node = work_queue.orderedRemove(closest_node_index);
|
||||||
|
|
||||||
|
for (closest_node.out_edges) |edge| {
|
||||||
|
const neighbor = edge.out_node;
|
||||||
|
const alternative_path = closest_node.work_distance + edge.distance;
|
||||||
|
|
||||||
|
if (alternative_path < neighbor.work_distance) {
|
||||||
|
neighbor.*.work_distance = alternative_path;
|
||||||
|
try work_map.put(neighbor, closest_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return destination.work_distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// B
|
||||||
|
// 4/ 1\
|
||||||
|
// A D
|
||||||
|
// 3\ 5/
|
||||||
|
// C
|
||||||
|
|
||||||
|
test "Can find shortest path between A and D" {
|
||||||
|
const page_allocator = std.heap.page_allocator;
|
||||||
|
|
||||||
|
var a = Node{ .out_edges = undefined, .label = "A", .work_distance = 0 };
|
||||||
|
var b = Node{ .out_edges = undefined, .label = "B", .work_distance = 0 };
|
||||||
|
var c = Node{ .out_edges = undefined, .label = "C", .work_distance = 0 };
|
||||||
|
var d = Node{ .out_edges = undefined, .label = "D", .work_distance = 0 };
|
||||||
|
|
||||||
|
const ab = Edge{ .in_node = &a, .out_node = &b, .distance = 4 };
|
||||||
|
const bd = Edge{ .in_node = &b, .out_node = &d, .distance = 1 };
|
||||||
|
|
||||||
|
const ac = Edge{ .in_node = &a, .out_node = &c, .distance = 3 };
|
||||||
|
const cd = Edge{ .in_node = &c, .out_node = &d, .distance = 5 };
|
||||||
|
|
||||||
|
a.out_edges = &[_]Edge{ ab, ac };
|
||||||
|
b.out_edges = &[_]Edge{bd};
|
||||||
|
c.out_edges = &[_]Edge{cd};
|
||||||
|
|
||||||
|
var nodes = [_]*Node{ &a, &b, &c, &d };
|
||||||
|
const graph = Graph{ .nodes = &nodes };
|
||||||
|
|
||||||
|
const shortest_path_a_d = try dijkstra(page_allocator, graph, &a, &d);
|
||||||
|
const shortest_path_b_d = try dijkstra(page_allocator, graph, &b, &d);
|
||||||
|
const shortest_path_a_c = try dijkstra(page_allocator, graph, &a, &c);
|
||||||
|
|
||||||
|
try expect(shortest_path_a_d == 5);
|
||||||
|
try expect(shortest_path_b_d == 1);
|
||||||
|
try expect(shortest_path_a_c == 3);
|
||||||
|
}
|
Reference in New Issue
Block a user