Dijkstras algorithm The idea reminiscent of BFS but
Dijkstra’s algorithm • The idea: reminiscent of BFS, but adapted to handle weights – Grow the set of nodes whose shortest distance has been computed – Nodes not in the set will have a “best distance so far” – A priority queue will turn out to be useful for efficiency Summer 2016 1 CSE 373: Data Structures & Algorithms
Dijkstra’s Algorithm: Idea 0 A 2 B 2 1 4 4 D 9 2 5 C 1 11 7 2 4 F 10 2 E 3 H 3 G 1 1 12 • Initially, start node has cost 0 and all other nodes have cost • At each step: – Pick closest unknown vertex v – Add it to the “cloud” of known vertices – Update distances for nodes with edges from v • That’s it! (But we need to prove it produces correct answers) Summer 2016 2 CSE 373: Data Structures & Algorithms
The Algorithm 1. For each node v, set v. cost = and v. known = false 2. Set source. cost = 0 3. While there are unknown nodes in the graph a) Select the unknown node v with lowest cost b) Mark v as known c) For each edge (v, u) with weight w, c 1 = v. cost + w // cost of best path through v to u c 2 = u. cost // cost of best path to u previously known if(c 1 < c 2){ // if the path through v is better u. cost = c 1 u. path = v // for computing actual paths } Summer 2016 3 CSE 373: Data Structures & Algorithms
Important features • When a vertex is marked known, the cost of the shortest path to that node is known – The path is also known by following back-pointers • While a vertex is still not known, another shorter path to it might still be found Summer 2016 4 CSE 373: Data Structures & Algorithms
0 A B 2 1 2 D 1 C 2 F Example #2 6 5 1 E 1 3 5 10 G vertex Order Added to Known Set: Summer 2016 5 known? cost A 0 B ? ? C ? ? D ? ? E ? ? F ? ? G ? ? path CSE 373: Data Structures & Algorithms
0 A B 2 1 1 2 C 2 F Example #2 6 5 D 1 E 1 3 5 10 G Order Added to Known Set: A Summer 2016 6 vertex known? cost A Y 0 path B ? ? C 2 A D 1 A E ? ? F ? ? G ? ? CSE 373: Data Structures & Algorithms
0 A 6 B 2 1 1 2 C 2 7 F Example #2 6 5 D 1 2 E 1 5 10 G 3 6 known? cost A Y 0 A, D 7 path B 6 D C 2 A 1 A E 2 D F 7 D G 6 D D Order Added to Known Set: Summer 2016 vertex Y CSE 373: Data Structures & Algorithms
0 A 6 B 2 1 1 2 C 2 4 F Example #2 6 5 D 1 2 E 1 5 10 G 3 6 known? cost A Y 0 B Order Added to Known Set: A, D, C Summer 2016 vertex 8 path 6 D C Y 2 A D Y 1 A E 2 D F 4 C G 6 D CSE 373: Data Structures & Algorithms
0 A 3 B 2 1 1 2 C 2 4 F Example #2 6 5 D 1 2 E 1 5 10 G 3 6 known? cost A Y 0 B Order Added to Known Set: A, D, C, E Summer 2016 vertex 9 path 3 E C Y 2 A D Y 1 A E Y 2 D F 4 C G 6 D CSE 373: Data Structures & Algorithms
Example #3 X 1 90 1 80 1 60 70 1 50 … Y How will the best-cost-so-far for Y proceed? Is this expensive? Summer 2016 10 CSE 373: Data Structures & Algorithms
Example #3 X 1 90 1 80 1 60 70 1 50 … Y How will the best-cost-so-far for Y proceed? 90, 81, 72, 63, 54, … Is this expensive? No, each edge is processed only once Summer 2016 11 CSE 373: Data Structures & Algorithms
A Greedy Algorithm • Dijkstra’s algorithm – For single-source shortest paths in a weighted graph (directed or undirected) with no negative-weight edges • An example of a greedy algorithm: – At each step, irrevocably does what seems best at that step • A locally optimal step, not necessarily globally optimal – Once a vertex is known, it is not revisited • Turns out to be globally optimal Summer 2016 12 CSE 373: Data Structures & Algorithms
Where are We? • Had a problem: Compute shortest paths in a weighted graph with no negative weights • Learned an algorithm: Dijkstra’s algorithm • What should we do after learning an algorithm? – Prove it is correct • Not obvious! • We will sketch the key ideas – Analyze its efficiency • Will do better by using a data structure we learned earlier! Summer 2016 13 CSE 373: Data Structures & Algorithms
Correctness: Intuition Rough intuition: All the “known” vertices have the correct shortest path – True initially: shortest path to start node has cost 0 – If it stays true every time we mark a node “known”, then by induction this holds and eventually everything is “known” Key fact we need: When we mark a vertex “known” we won’t discover a shorter path later! – This holds only because Dijkstra’s algorithm picks the node with the next shortest path-so-far – The proof is by contradiction… Summer 2016 14 CSE 373: Data Structures & Algorithms
Correctness: The Cloud (Rough Sketch) v Better path to v? No! w Next shortest path from inside the known cloud The Known Cloud Source Suppose v is the next node to be marked known (“added to the cloud”) • The best-known path to v must have only nodes “in the cloud” – Else we would have picked a node closer to the cloud than v • Suppose the actual shortest path to v is different – It won’t use only cloud nodes, or we would know about it – So it must use non-cloud nodes. Let w be the first non-cloud node on this path. The part of the path up to w is already known and must be shorter than the best-known path to v. So v would not have been picked. Contradiction. Summer 2016 CSE 373: Data Structures 15 & Algorithms
Naïve asymptotic running time • So far: O(|V|2) • We had a similar “problem” with topological sort being O(|V|2) due to each iteration looking for the node to process next – We solved it with a queue of zero-degree nodes – But here we need the lowest-cost node and costs can change as we process edges • Solution? Summer 2016 16 CSE 373: Data Structures & Algorithms
Improving asymptotic running time • So far: O(|V|2) • We had a similar “problem” with topological sort being O(|V|2) due to each iteration looking for the node to process next – We solved it with a queue of zero-degree nodes – But here we need the lowest-cost node and costs can change as we process edges • Solution? – A priority queue holding all unknown nodes, sorted by cost – But must support decrease. Key operation • Must maintain a reference from each node to its current position in the priority queue • Conceptually simple, but can be a pain to code up Summer 2016 17 CSE 373: Data Structures & Algorithms
Efficiency, second approach Use pseudocode to determine asymptotic run-time dijkstra(Graph G, Node start) { for each node: x. cost=infinity, x. known=false start. cost = 0 build-heap with all nodes while(heap is not empty) { b = delete. Min() b. known = true for each edge (b, a) in G if(!a. known) if(b. cost + weight((b, a)) < a. cost){ decrease. Key(a, “new cost – old cost”) a. path = b } } Summer 2016 18 CSE 373: Data Structures & Algorithms
Efficiency, second approach Use pseudocode to determine asymptotic run-time dijkstra(Graph G, Node start) { for each node: x. cost=infinity, x. known=false O(|V|) start. cost = 0 build-heap with all nodes while(heap is not empty) { O(|V|log|V|) b = delete. Min() b. known = true for each edge (b, a) in G if(!a. known) if(b. cost + weight((b, a)) < a. cost){ O(|E|log|V|) decrease. Key(a, “new cost – old cost”) a. path = b } } O(|V|log|V|+|E|log|V|) Summer 2016 19 CSE 373: Data Structures & Algorithms
CSE 373: Data Structures & Algorithms Software-Design Interlude – Preserving Abstractions Hunter Zahn Summer 2016 CSE 373: Data Structures & Algorithms 20
Motivation • Essential: knowing available data structures and their trade-offs – You’re taking a whole course on it! • However, you will rarely if ever re-implement these “in real life” – Provided by libraries • But the key idea of an abstraction arises all the time “in real life” – Clients do not know how it is implemented – Clients do not need to know – Clients cannot “break the abstraction” no matter what they do Summer 2016 21 CSE 373: Data Structures & Algorithms
Interface vs. implementation • Provide a reusable interface without revealing implementation • More difficult than it sounds due to aliasing and field-assignment – Some common pitfalls • So study it in terms of ADTs vs. data structures – Will use priority queues as example in lecture, but any ADT would do – Key aspect of grading your homework on graphs Summer 2016 22 CSE 373: Data Structures & Algorithms
Recall the abstraction Clients: “not trusted by ADT implementer” • Can perform any sequence of ADT operations • Can do anything type-checker allows on any accessible objects Summer 2016 Data structure: new PQ(…) • Should document how operations can be used and insert(…) what is checked (raising appropriate exceptions) delete. Min(…) – E. g. , parameter for method x not null is. Empty() • If used correctly, correct priority queue for any client • Client “cannot see” the implementation – E. g. , binary min heap 23 CSE 373: Data Structures & Algorithms
Our example • A priority queue with to-do items, so earlier dates “come first” – Simpler example than using Java generics • Exact method names and behavior not essential to example public class Date { … // some private fields (year, month, day) public int get. Year() {…} public void set. Year(int y) {…} … // more methods Summer 2016 } public class To. Do. Item { … // some private fields (date, description) public void set. Date(Date d) {…} public void set. Description(String d) {…} … // more methods } CSE 373: Data Structures & // continued 24 next slide… Algorithms
Our example • A priority queue with to-do items, so earlier dates “come first” – Simpler example than using Java generics • Exact method names and behavior not essential to example public class Date { … } public class To. Do. Item { … } public class To. Do. PQ { … // some private fields (array, size, …) public To. Do. PQ() {…} void insert(To. Do. Item t) {…} To. Do. Item delete. Min() {…} boolean is. Empty() {…} } CSE 373: Data Structures & Summer 2016 25 Algorithms
An obvious mistake • Why we trained you to “mindlessly” make fields private: public class To. Do. PQ { … // other fields public To. Do. Item[] heap; public To. Do. PQ() {…} void insert(To. Do. Item t) {…} … } // client: pq = new To. Do. PQ(); pq. heap = null; pq. insert(…); // likely exception • Today’s lecture: private does not solve all your problems! – Upcoming pitfalls can occur even with all private fields Summer 2016 26 CSE 373: Data Structures & Algorithms
Less obvious mistakes public class To. Do. PQ { … // all private fields public To. Do. PQ() {…} void insert(To. Do. Item i) {…} … } // client: To. Do. PQ pq = new To. Do. PQ(); To. Do. Item i = new To. Do. Item(…); pq. insert(i); i. set. Description(“some different thing”); pq. insert(i); // same object after update x = delete. Min(); // x’s description? ? ? y = delete. Min(); // y’s description? ? ? Summer 2016 27 CSE 373: Data Structures & Algorithms
Aliasing and mutation year: … month: … … date: description: “…” i pq heap: size: 1 … • Client was able to update something inside the abstraction because client had an alias to it! – It is too hard to reason about and document what should happen, so better software designs avoid the issue! Summer 2016 28 CSE 373: Data Structures & Algorithms
More bad clients To. Do. PQ pq = new To. Do. PQ(); To. Do. Item i 1 = new To. Do. Item(…); // To. Do. Item i 2 = new To. Do. Item(…); // pq. insert(i 1); pq. insert(i 2); i 1. set. Date(…); // year 2015 x = delete. Min(); // “wrong” (? ? ? ) // What date does returned Summer 2016 29 year 2013 year 2014 item? item have? ? ? CSE 373: Data Structures & Algorithms
More bad clients i 2 i 1 pq Summer 2016 date: description: “…” year: … month: … … heap: size: 2 … 30 CSE 373: Data Structures & Algorithms
More bad clients pq = new To. Do. PQ(); To. Do. Item i 1 = new To. Do. Item(…); pq. insert(i 1); i 1. set. Date(null); To. Do. Item i 2 = new To. Do. Item(…); pq. insert(i 2); // Null. Pointer. Exception? ? ? Get exception inside data-structure code even if insert did a careful check that the date in the To. Do. Item is not null • Bad client later invalidates the check Summer 2016 31 CSE 373: Data Structures & Algorithms
The general fix • Avoid aliases into the internal data (the “red arrows”) by copying objects as needed – Do not use the same objects inside and outside the abstraction because two sides do not know all mutation (field-setting) that might occur – “Copy-in-copy-out” • A first attempt: Summer 2016 public class To. Do. PQ { … void insert(To. Do. Item i) { To. Do. Item internal_i = new To. Do. Item(i. date, i. description); … // use only the internal object } } 32 CSE 373: Data Structures & Algorithms
Must copy the object public class To. Do. PQ { … void insert(To. Do. Item i) { To. Do. Item internal_i = new To. Do. Item(i. date, i. description); … // use only the internal object } } • Notice this version accomplishes nothing – Still the alias to the object we got from the client: Summer 2016 public class To. Do. PQ { … void insert(To. Do. Item i) { To. Do. Item internal_i = i; … // internal_i refers to same object } } CSE 373: Data Structures & 33 Algorithms
Copying works… i year: … month: … … date: description: “…” pq heap: size: 1 … To. Do. Item i = new To. Do. Item(…); pq = new To. Do. PQ(); pq. insert(i); i. set. Description(“some different thing”); pq. insert(i); x = delete. Min(); y = delete. Min(); Summer 2016 34 CSE 373: Data Structures & Algorithms
Didin’t do enough copying yet year: … month: … … i date: description: “…” pq heap: size: 1 … Date d = new Date(…) To. Do. Item i = new To. Do. Item(d, “buy beer”); pq = new To. Do. PQ(); pq. insert(i); d. set. Year(2015); … Summer 2016 35 CSE 373: Data Structures & Algorithms
Deep copying • For copying to work fully, usually need to also make copies of all objects referred to (and that they refer to and so on…) – All the way down to int, double, String, … – Called deep copying (versus our first attempt shallow-copy) • Rule of thumb: Deep copy of things passed into abstraction Summer 2016 public class To. Do. PQ { … void insert(To. Do. Item i) { To. Do. Item internal_i = new To. Do. Item(new Date(…), i. description); … // use only the internal object } CSE 373: Data Structures & } 36 Algorithms
Constructors take input too • General rule: Do not “trust” data passed to constructors – Check properties and make deep copies • Example: Floyd’s algorithm for build. Heap should: – Check the array (e. g. , for null values in fields of objects or array positions) – Make a deep copy: new array, new objects public class To. Do. PQ { // a second constructor that uses // Floyd’s algorithm, but good design // deep-copies the array (and its contents) void Priority. Queue(To. Do. Item[] items) { … } } Summer 2016 37 CSE 373: Data Structures & Algorithms
That was copy-in, now copy-out… • So we have seen: – Need to deep-copy data passed into abstractions to avoid pain and suffering • Next: – Need to deep-copy data passed out of abstractions to avoid pain and suffering (unless data is “new” or no longer used in abstraction) • Then: – If objects are immutable (no way to update fields or things they refer to), then copying unnecessary Summer 2016 38 CSE 373: Data Structures & Algorithms
delete. Min is fine public class To. Do. PQ { … To. Do. Item delete. Min() { To. Do. Item ans = heap[0]; … // algorithm involving percolate. Down return ans; } • Does not create a “red arrow” because object returned is no longer part of the data structure • Returns an alias to object that was in the heap, but now it is not, so conceptual “ownership” “transfers” to the client Summer 2016 39 CSE 373: Data Structures & Algorithms
get. Min needs copying year: … month: … … date: description: “…” x pq heap: size: 1 … To. Do. Item i = new To. Do. Item(…); pq = new To. Do. PQ(); x = pq. get. Min(); x. set. Date(…); public class To. Do. PQ { To. Do. Item get. Min() { int ans = heap[0]; return ans; } } • Uh-oh, creates a “red arrow” Summer 2016 40 CSE 373: Data Structures & Algorithms
The fix • Just like we deep-copy objects from clients before adding to our data structure, we should deep-copy parts of our data structure and return the copies to clients • Copy-in and copy-out public class To. Do. PQ { To. Do. Item get. Min() { int ans = heap[0]; return new To. Do. Item(new Date(…), ans. description); } } Summer 2016 41 CSE 373: Data Structures & Algorithms
Less copying • (Deep) copying is one solution to our aliasing problems • Another solution is immutability – Make it so nobody can ever change an object or any other objects it can refer to (deeply) – Allows “red arrows”, but immutability makes them harmless • In Java, a final field cannot be updated after an object is constructed, so helps ensure immutability – But final is a “shallow” idea and we need “deep” immutability Summer 2016 42 CSE 373: Data Structures & Algorithms
This works public class Date { private final int year; private final String month; private final String day; } public class To. Do. Item { private final Date date; private final String description; } public class To. Do. PQ { void insert(To. Do. Item i){/*no copy-in needed!*/} To. Do. Item get. Min(){/*no copy-out needed!*/} … } Notes: • String objects are immutable in Java • (Using String for month and day is not great style though) Summer 2016 43 CSE 373: Data Structures & Algorithms
This does not work public class Date { private final int year; private String month; // not final private final String day; … } public class To. Do. Item { private final Date date; private final String description; } public class To. Do. PQ { void insert(To. Do. Item i){/*no copy-in*/} To. Do. Item get. Min(){/*no copy-out*/} … } Client could mutate a Date’s month that is in our data structure • So must do entire deep copy of To. Do. Item Summer 2016 44 CSE 373: Data Structures & Algorithms
final is shallow public class To. Do. Item { private final Date date; private final String description; } • Here, final means no code can update the date or description fields after the object is constructed • So they will always refer to the same Date and String objects • But what if those objects have their contents change – Cannot happen with String objects – For Date objects, depends how we define Date • So final is a “shallow” notion, but we can use it “all the way down” to get deep immutability Summer 2016 45 CSE 373: Data Structures & Algorithms
This works • When deep-copying, can “stop” when you get to immutable data – Copying immutable data is wasted work, so poor style public class Date { // immutable private final int year; private final String month; private final String day; … } public class To. Do. Item { private Date date; private String description; } public class To. Do. PQ { To. Do. Item get. Min(){ int ans = heap[0]; return new To. Do. Item(ans. date, // okay! ans. description); } CSE 373: Data Structures & Summer 2016 } 46 Algorithms
What about this? public class Date { // immutable … } public class To. Do. Item { // immutable (unlike last slide) … } public class To. Do. PQ { // a second constructor that uses // Floyd’s algorithm void Priority. Queue(To. Do. Item[] items) { // what copying should we do? … } } Summer 2016 47 CSE 373: Data Structures & Algorithms
What about this? public class Date { // immutable … } public class To. Do. Item { // immutable (unlike last slide) … } public class To. Do. PQ { // a second constructor that uses // Floyd’s algorithm void Priority. Queue(To. Do. Item[] items) { // what copying should we do? … } } Copy the array, but do not copy the To. Do. Item or Date objects Summer 2016 48 CSE 373: Data Structures & Algorithms
Homework 4 • You are implementing a graph abstraction • As provided, Vertex and Edge are immutable – But Collection<Vertex> and Collection<Edge> are not • You might choose to add fields to Vertex or Edge that make them not immutable – Leads to more copy-in-copy-out, but that’s fine! • Or you might leave them immutable and keep things like “bestpath-cost-so-far” in another dictionary (e. g. , a Hash. Map) There is more than one good design, but preserve your abstraction – Great practice with a key concept in software design Summer 2016 49 CSE 373: Data Structures & Algorithms
- Slides: 49