Dijkstra's shortest path algorithm:
Dijkstra's algorithm is very similar to Prim's algorithm for minimum spanning tree. Like Prim's MST, we generate a SPT (shortest path tree) with a given source as root. (单源最短路)The basic idea is that we maintain two sets, one set contains vertices included in shortest path tree, other set includes vertices not yet included in shortest path tree. At every step of the algorithm, we find a vertex which is in the set and has a minimum distance from the source.
Below are the detailed steps used in Dijkstra's algorithm to find the shortest path from a single source vertex to all other vertices in the given graph:
Algorithm:
1) Create a set sptSet (shortest path tree set) that keeps track of vertices included in shortest path tree -> whose minimum distance from the source is calculated and finalized. Initially, the set is empty.
2) Assign a distance value(d[] array) to all vertices in the input graph. Initialize all distance values as INFINITE. Assign distance value as 0 for the source vertex so that it is picked first.
(The purpose of d[] array is to hold the minimal distance from a given vertex to the source)
3) While sptSet doesn't include all vertices:
a) Pick a vertex u which is not there in sptSet and has minimal distance value
b) include u to sptSet
c) Update distance value of all adjacent vertices to u. To update the distance values, iterate through all adjacent vertices. For every adjacent vertex v, if the sum of distance value of u ( from the source) and weight of edge u-v, is less than the distance value of v, then update the distance value of v. (so distance value might be the shortest the distance from the source to a given point? Yes)
伪代码:
清除所有点的标号
设d[0] = 0,其他d[i] = INF
循环n次 {
在所有未标号结点中,选出d值最小的结点x
给结点x标记
对于从x出发的所有边(x, y),更新d[y] = min{d[y], d[x] + w(x, y)}
}
class Dijkstra {
static final int V = 9;
void dijkstra(int graph[][], int src) {
//The output array will hold the shortest distance src to i
int dist[] = new int[V];
//sptSet[i] will be true if vertex i is **included in shortest path tree or
//shortest distance from src to i is finalized**
Boolean sptSet[] = new Boolean[V];
//initialization
for (int i = 0; i < V; i++) {
dist[i] = Integer.MAX_VALUE;
sptSet[i] = false;
}
//Distance from the source vertex to itself will always be 0
dist[src] = 0;
for (int count = 0; count < V - 1; count++) {
int u = minDistance(dist, sptSet);
sptSet[u] = true;
for (int v = 0; v < V; v++) {
//when u is the src, it just processes all the points that are adjacent to src
//notice that dist[u] is the distance from vertex u to src
if (!sptSet[v] && graph[u][v] != 0 && dist[u] + graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}
}
printSolution(dist, V);
}
int minDistance(int dist[], Boolean sptSet[]) {
int min = Integer.MAX_VALUE, min_index = -1;
for (int v = 0; v < V; v++) {
if (sptSet[v] == false && dist[v] < min) {
min = dist[v];
min_index = v;
}
}
return min_index;
}
void printSolution(int dist[], int n) {
System.out.println("Vertex Distance from Source");
for (int i = 0; i < V; i++) {
System.out.println(dist[i]);
}
}
}
Notes:
1) The code is for undirected graph, same dijkstra funciton can be used for directed grpah also.
2) The code finds shortest distances from source to all vertices. If we are interested only in shortest distance from the source to a single target, we can break the for loop when the picked minimum distance vertex is equal to target.
3) Time complexity of the implementation is O(V^2). Nevertheless, the time complexity can be reduced to O(E log V) (where E is the number of edges and V is the nubmer of vertices).
4) Notice that the Dijkstra's algorithm doesn't work for graphs with negative weight edges -> use Bellman-Ford Algorithm instead. (Think about why)
Optimazation:
Main Idea: use the adjacency list representation and with the help of min/max heap.
Justification: In reality, the number of edges is far less than that of vertices, so is far less than .
Detailed steps:
1) Create a Min Heap of size V where V is the nubmer of vertices in the given graph. Every node of min heap contains vetex nubmer and distance of the vertex
2) Initialize Min Heap with source vetex as root (the distance value assigned to source vertex is 0). The distance value assigned to all other vertices is INF(infinite).
3) While Min Heap is not empty, do following:
a) Extract the vetex with minimum distance value node from Min Heap. Let the extracted vertex be u.
b) For every adjacent vertex v of u, check if v is in Min Heap. If v is in Min Heap and distance value is more than the weight of
u-v plus distance value of u, then update the distance value of v.
邻接表:
//每个结点i都有一个链表,里面保存着从i出发的所有边。对于无向图来说,每条
//边会在邻接表中出现两次。实现:首先给每条边编号,然后用first[u]保存结点u的
//第一条边的编号,next[e]表示编号为e的“下一条”边的编号
int n, m;
int first[maxn];
int u[maxm], v[maxm], w[maxm], next[maxm];
void readGraph() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) first[i] = -1;
for (int e = 0; e < m; e++) {
scanf("%d%d%d", &u[e], &v[e], &w[e]);
next[e] = first[u[e]];
first[u[e]] = e;
}
}
Implementation based on vector (Idea of adjacency list):
struct Dijkstra {
int n, m;
vector edges;
vector G[maxn];
bool done[maxn];
int d[maxn];
int p[maxn];
void init(int n) {
this -> n = n;
//The adjacency list based on the vector
for (int i = 0; i < n; i++) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int dist) {
edges.push_back(Edge(from, to, dist));
m = edges.size();
G[from].push_back(m - 1);
}
}
struct Edge {
int from, int to, dist;
Edge(int u, int v, int d): from(u), to(v), dist(d) {}
};
Use Min Heap to optimize the speed:
struct HeapNode {
int d, u; //d is the distance from the vertex u to source; u is the vertex u
bool operator < (const HeapNode& rhs) const {
return d > rhs.d;
}
};
void dijkstra(int s) {
priority_queue Q;
for (int i = 0; i < n; i++) d[i] = INF:
d[s] = 0;
memset(done, 0, sizeof(done));
Q.push((HeapNode){0, s});
while (!Q.empty()) {
HeapNode x = Q.top(); Q.pop();
int u = x.u;
if (done[u]) continue;
for (int i = 0; i < G[u].size(); i++) {
Edge& e = edges[G[u][i]];
if (d[e.to] > d[u] + e.dist) {
d[e.to] = d[u] + e.dist;
p[e.to] = G[u][i]; //For the purpose of printing the shortest single source path
Q.push((HeapNode) {d[e.to], e.to});
}
}
}
}