|
| 1 | +# Dijkstra's Algorithm |
| 2 | + |
| 3 | +## Motivating Problem |
| 4 | + |
| 5 | +Imagine that we have a graph of flights across the country, and each flight has a given cost and time. |
| 6 | + |
| 7 | +We want to find a series of flights from city _A_ to city _B_ such that the cost (or time) is minimized. |
| 8 | + |
| 9 | +We can generalize this problem to the following: |
| 10 | + |
| 11 | +Given a graph _G_ and a starting vertex _s_, what is the _shortest path_ from _s_ to any other vertex of _G_? |
| 12 | + |
| 13 | +This problem is called the _Single-Source Shortest Paths_ (SSSP) problem. |
| 14 | + |
| 15 | +## Single=Source Shortest Path |
| 16 | + |
| 17 | +#### SSSP on an unweighted graph |
| 18 | + |
| 19 | +If the graph is unweighted (or if all of the edges have equal or constant weight), we can use the BFS algorithm in order to solve this problem. |
| 20 | + |
| 21 | +BFS goes "level-by-level", so it would visit all vertices that are one unit away first, and then two units away, and then three units away, etc. |
| 22 | + |
| 23 | +The fact that BFS visits vertices of a graph "level-by-level" from a source vertex turns BFS into a natural choice to solve the SSSP problem on unweighted graphs. |
| 24 | + |
| 25 | +### SSSP on a weighted graph |
| 26 | + |
| 27 | +If the given graph is weighted, BFS no longer works. This is because there can be "longer" paths from the source to vertex, but has a smaller cost than the "shorter" path found by BFS. |
| 28 | + |
| 29 | +To solve the SSSP problem on weighted graphs, we use a greedy algorithm: _Dijkstra's Algorithm_ |
| 30 | + |
| 31 | +## Dijkstra's Algorithm |
| 32 | + |
| 33 | +### Procedure |
| 34 | + |
| 35 | +1. Give every vertex a tentative distance |
| 36 | + - the initial vertex will have a distance of zero |
| 37 | + - every other vertex will have a distance of infinity |
| 38 | +2. Set the initial vertex as the current vertex; mark all other vertices unvisited |
| 39 | +3. For the current vertex, consider all of its unvisited neighbors and calculate the tentative distance to each vertex; compare the newly calculated distance to the current assigned value and set the tentative distance to the smaller distance |
| 40 | +4. When we are done considering all of the neighbors of the current vertex, mark the current vertex as visited |
| 41 | +5. If the destination vertex has been marked visit, or if the smallest tentative distance among unvisited vertices is infinity, stop the algorithm |
| 42 | +6. Select the unvisited vertex that is marked with the smallest tentative distance, and set it as the new current vertex, then go back to step 3 |
| 43 | + |
| 44 | + |
| 45 | + |
| 46 | +Above is a visual representation of Dijkstra's Algorithm |
| 47 | + |
| 48 | +### Coding Dijkstra's Algorithm |
| 49 | + |
| 50 | +There are several ways to implement this algorithm |
| 51 | +- `int[] distance` |
| 52 | +- `PriorityQueue<Vertex>` |
| 53 | + |
| 54 | +#### Using an array |
| 55 | + |
| 56 | +```java |
| 57 | +// This array will keep track of the tentative distance up to each vertex |
| 58 | +int[] distance = new int[ N ]; |
| 59 | +// This array will tell us if we have visited a vertex or not |
| 60 | +boolean[] visited = new boolean[ N ]; |
| 61 | + |
| 62 | +// Mark the tentative distance of the starting vertex as zero |
| 63 | +distance[ start ] = 0; |
| 64 | +// Set the current vertex as the starting vertex |
| 65 | +int current = start; |
| 66 | + |
| 67 | +// While we have not reached our destination... |
| 68 | +while ( !visited[ destination ] ) |
| 69 | +{ |
| 70 | + // Mark the current vertex as visited |
| 71 | + visited[ current ] = true; |
| 72 | + // Get the neighboring vertices of the current vertex |
| 73 | + ArrayList<Integer> neighbors = graph[ current ]; |
| 74 | + |
| 75 | + // For each of the neighbors of the current vertex... |
| 76 | + for ( int neighbor : neighbors ) |
| 77 | + { |
| 78 | + // Calculate the new distance to the neighbor |
| 79 | + // This can be calculated by taking the tentative distance up to the current vertex and adding the |
| 80 | + // cost to go from the current vertex to the neighbor |
| 81 | + int newDistance = distances[ current ] + costs[ current ][ neighbor ]; |
| 82 | + |
| 83 | + // If this new distance we calculated is smaller than the current tentative distance of the neighbor... |
| 84 | + if ( newDistance < distances[ neighbor ] ) |
| 85 | + { |
| 86 | + // Update the tentative distance of the neighbor with this new distance |
| 87 | + distances[ neighbor ] = newDistance; |
| 88 | + } |
| 89 | + } |
| 90 | + |
| 91 | + // We now need to calculate the new current vertex, which will be the vertex with the smallest tentative |
| 92 | + // distance that we have yet to visit in the graph |
| 93 | + |
| 94 | + // This will keep track of the next vertex that we will set as the current vertex |
| 95 | + int index = -1; |
| 96 | + // This will keep track of the minimum tentative distance of the next current vertex |
| 97 | + int min = Integer.MAX_VALUE; |
| 98 | + |
| 99 | + // For each of the vertices in the graph... |
| 100 | + for ( int j = 0; j < N; j++ ) |
| 101 | + { |
| 102 | + // If we have not visited the vertex and the tentative distance of the vertex is smaller than our current min... |
| 103 | + if ( !visited[ j ] && distances[ j ] < min ) |
| 104 | + { |
| 105 | + // Update the index with the vertex |
| 106 | + index = j; |
| 107 | + // Update the min distance value |
| 108 | + min = distances[ j ]; |
| 109 | + } |
| 110 | + } |
| 111 | + |
| 112 | + // If we were unable to find another vertex to visit... |
| 113 | + if ( index == -1 ) |
| 114 | + { |
| 115 | + // Break out of the loop |
| 116 | + break; |
| 117 | + } |
| 118 | + |
| 119 | + // Update the current vertex |
| 120 | + current = index; |
| 121 | +} |
| 122 | +``` |
0 commit comments