10/19/2018 Dijkstra's shortest path algorithm

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 mlog(n) is far less than n^2

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<Edge> edges;
	vector<int> 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<HeapNode> 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});
                }
            }
        }
    }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值