diff --git a/graph-search/notes.md b/graph-search/notes.md index 2895d5069e1387252e3655919f124a95ae3de707..03f649113f94bfbd9659c4915b6a2a6fb908dd92 100644 --- a/graph-search/notes.md +++ b/graph-search/notes.md @@ -4,11 +4,13 @@ Please clone the starter code linked from Canvas (with `git clone --recursive` s In the weighted directed graph to the right, what is the shortest path from `a` to `d`? +* `a` → `c` → `e` → `f` → `d` (length 14) + # Problem 2: For a certain puzzle played on a string of digits, each move may slide any digit `x` left `x` places or right `x` places, as long as there is room. For example, the `4` in `123456789` can move right four spots: -> 123456789 +> 123456789 > >>>> which gives @@ -17,11 +19,14 @@ which gives but it cannot move left, because trying would move it past the end of the string: -> 123456789 +> 123456789 > <<<< How many moves does it take to reverse the string `123`? +* Four moves: `123` → `213` → `231` → `312` → `321` +* Four moves: `123` → `213` → `132` → `312` → `321` + --------------------------------------------------------------------- # Worklist Algorithms for Graph Search @@ -31,45 +36,70 @@ How many moves does it take to reverse the string `123`? ## Depth-First Search (DFS) -* Worklist: … +* Worklist: Stack * Guaranteed to find a path if one exists * Not guaranteed to find a good path * Can be made very memory efficient (topic for a later class) Worklist Backpointers -------- ------------ - (⊥, a) + (⊥, a) ✓ a → (⊥, a) + (a, c) ✓ c → (a, c) + (c, e) b → (c, b) + (c, b) ✓ e → (b, e) + (b, e) ✓ f → (e, f) + (b, a) ✓ d → (f, d) + (e, d) + (e, f) ✓ + (f, c) + (f, d) ✓ Reversed Path ---- - … + d ← f ← e ← b ← c ← a ## 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 traveled 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 diff --git a/graph-search/src/features/search/search.js b/graph-search/src/features/search/search.js index 31b77d22b5cae58d63a29835471891eddb666e4f..86a91cc8b90ef22a0df1eb259c5e2dc70643abb1 100644 --- a/graph-search/src/features/search/search.js +++ b/graph-search/src/features/search/search.js @@ -9,33 +9,86 @@ class Edge { } export function dfs(graph, source, destination) { - // // SEARCH: - // // base case - // // initiation - // while (…) { // termination condition - // // consecution (part i) - // // action - // if (…) { // early termination conditional - // // POSTPROCESSING: - // // base case - // for(…; // initiation - // …; // termination condition - // …) { // consecution - // // action - // } - // return …; - // } - // // consecution (part ii) - // } - return undefined; // TODO: stub + // SEARCH: + const backpointers = new Map(); + const worklist = []; + worklist.push(new Edge(undefined, source)); + while (worklist.length > 0) { + const workitem = worklist.pop(); + if (backpointers.has(workitem.to)) { + continue; + } + backpointers.set(workitem.to, workitem); + if (workitem.to === destination) { + // POSTPROCESSING: + const reversedPath = []; + for (let current = workitem.to; + current !== undefined; + current = backpointers.get(current).from) { + reversedPath.push(current); + } + return reversedPath.reverse(); + } + for (const incidence of graph.getIncidences(workitem.to)) { + worklist.push(new Edge(workitem.to, incidence.destination)); + } + } + return undefined; } 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 = workitem.to; + 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) { diff --git a/graph-search/src/features/search/solution.js b/graph-search/src/features/search/solution.js index 69644f05b7179674513f148f766ecd8ae3c0b252..a64ab4729a95691560c0aae8d3e2fe73cbf91fb3 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 = dijkstras; const firstSolution = search(firstExample, 'a', 'd'); const secondSolution = search(secondExample, '123', '321'); return (