From 06d8916b365d6567dca21d36a0458386ca636e87 Mon Sep 17 00:00:00 2001 From: "Brady J. Garvin" <bgarvin@cse.unl.edu> Date: Thu, 6 Oct 2022 16:24:30 -0500 Subject: [PATCH] Designed, traced, and coded other iterative graph searches. --- graph-search/notes.md | 53 ++++++++---- graph-search/src/features/search/search.js | 87 +++++++++++++++++++- graph-search/src/features/search/solution.js | 2 +- 3 files changed, 122 insertions(+), 20 deletions(-) diff --git a/graph-search/notes.md b/graph-search/notes.md index 9414791..7d29ac8 100644 --- a/graph-search/notes.md +++ b/graph-search/notes.md @@ -61,51 +61,74 @@ In the weighted directed graph on the whiteboard, what is the shortest path from ## Breadth-First Search (BFS) -* Worklist: … +* Worklist: Queue * Guaranteed to find a path with the fewest edges Worklist Backpointers -------- ------------ - (⊥, a) + (⊥, a) ✓ a → (⊥, a) + (a, c) ✓ c → (a, c) + (c, e) ✓ e → (c, e) + (c, b) ✓ b → (c, b) + (e, d) ✓ d → (e, d) + (e, f) + (b, e) + (b, a) Reversed Path ---- - … + d ← e ← c ← a ## Dijkstra's Algorithm -* Worklist: … -* Priority: … +* Worklist: Priority Queue +* Priority: Distance travelled from the source * Guaranteed to find a path with least weight Worklist Backpointers ------------ -------------- - (⊥, a, 0) + (⊥, a, 0) ✓ a → (⊥, a, 0) + (a, c, 7) ✓ c → (a, c, 7) + (c, e, 12) ✓ b → (c, b, 8) + (c, b, 8) ✓ e → (c, e, 12) + (b, e, 17) f → (e, f, 14) + (b, a, 12) ✓ d → (f, d, 14) + (e, d, 15) + (e, f, 14) ✓ + (f, c, 22) + (f, d, 14) ✓ Reversed Path ---- - … + d ← f ← e ← c ← a ## Best-First Search -* Worklist: … -* Priority: … +* Worklist: Priority Queue +* Priority: Distance travelled from the source plus estimated distance still to travel * Guaranteed to find a path if one exists * Not guaranteed to find a good path (but often does anyway) * Can have good best- and average-case time efficiency - Worklist Backpointers - ------------ -------------- - (⊥, a, 0) + Worklist Backpointers + ----------------- -------------- + (⊥, a, 0) → 2 ✓ a → (⊥, a, 0) + (a, c, 7) → 9 ✓ c → (a, c, 7) + (c, e, 12) → 13 ✓ b → (c, b, 8) + (c, b, 8) → 9 ✓ e → (c, e, 12) + (b, a, 12) → 14 ✓ d → (e, d, 15) + (b, e, 17) → 18 + (e, d, 15) → 15 ✓ + (e, f, 14) → 16 Reversed Path ---- - … + d ← e ← c ← a ## A* -* Worklist: … -* Priority: … +* Worklist: Priority Queue +* Priority: Distance travelled from the source plus estimated distance still to travel (estimates computed with an *admissible* heuristic) * Guaranteed to find a path with least weight * Can have good best- and average-case time efficiency diff --git a/graph-search/src/features/search/search.js b/graph-search/src/features/search/search.js index a30fcf5..b60729c 100644 --- a/graph-search/src/features/search/search.js +++ b/graph-search/src/features/search/search.js @@ -37,19 +37,98 @@ export function dfs(graph, source, destination) { } export function bfs(graph, source, destination) { - return undefined; // TODO: stub + const backpointers = new Map(); + const worklist = new Queue(); + worklist.insert(new Edge(undefined, source)); + while (worklist.size > 0) { + const workitem = worklist.remove(); + if (backpointers.has(workitem.to)) { + continue; + } + backpointers.set(workitem.to, workitem); + if (workitem.to === destination) { + const reversedPath = []; + for (let current = destination; + current !== undefined; + current = backpointers.get(current).from) { + reversedPath.push(current); + } + return reversedPath.reverse(); + } + for (const incidence of graph.getIncidences(workitem.to)) { + worklist.insert(new Edge(workitem.to, incidence.destination)); + } + } + return undefined; } export function dijkstras(graph, source, destination) { - return undefined; // TODO: stub + const backpointers = new Map(); + const worklist = new PriorityQueue(); + worklist.insert(new Edge(undefined, source, 0), 0); + while (worklist.size > 0) { + const workitem = worklist.remove(); + if (backpointers.has(workitem.to)) { + continue; + } + backpointers.set(workitem.to, workitem); + if (workitem.to === destination) { + const reversedPath = []; + for (let current = destination; + current !== undefined; + current = backpointers.get(current).from) { + reversedPath.push(current); + } + return reversedPath.reverse(); + } + for (const incidence of graph.getIncidences(workitem.to)) { + worklist.insert( + new Edge(workitem.to, incidence.destination, workitem.distance + incidence.weight), + workitem.distance + incidence.weight, + ); + } + } + return undefined; } function heuristic(vertex, destination) { - return 0; // TODO: stub + if ('acf'.includes(vertex)) { + return 2; + } + if ('be'.includes(vertex)) { + return 1; + } + return 0; } export function bestFirst(graph, source, destination) { - return undefined; // TODO: stub + const backpointers = new Map(); + const worklist = new PriorityQueue(); + worklist.insert(new Edge(undefined, source, 0), heuristic(source, destination)); + while (worklist.size > 0) { + const workitem = worklist.remove(); + if (backpointers.has(workitem.to) && + backpointers.get(workitem.to).distance <= workitem.distance) { + continue; + } + backpointers.set(workitem.to, workitem); + if (workitem.to === destination) { + const reversedPath = []; + for (let current = destination; + current !== undefined; + current = backpointers.get(current).from) { + reversedPath.push(current); + } + return reversedPath.reverse(); + } + for (const incidence of graph.getIncidences(workitem.to)) { + worklist.insert( + new Edge(workitem.to, incidence.destination, workitem.distance + incidence.weight), + workitem.distance + incidence.weight + heuristic(incidence.destination, destination), + ); + } + } + return undefined; } export function recursiveDFS(graph, source, destination) { diff --git a/graph-search/src/features/search/solution.js b/graph-search/src/features/search/solution.js index 69644f0..da0ee23 100644 --- a/graph-search/src/features/search/solution.js +++ b/graph-search/src/features/search/solution.js @@ -29,7 +29,7 @@ function formatSolution(solution) { } export function Solution(props) { - const search = dfs; + const search = bestFirst; const firstSolution = search(firstExample, 'a', 'd'); const secondSolution = search(secondExample, '123', '321'); return ( -- GitLab