首页 > 代码库 > Dijkstra 算法

Dijkstra 算法

dijkstra算法,最简单的实现需要$O(|V|^2)$。用binary heap实现,可以优化到O((|V|+|E|)lg|V|),如果用fibonacci heap的话,可以优化到O(|E|+|V|lg|V|)。如果图是密集图的话,那这个优化效果也不好,接近$O(|V|^2)$。

For any implementation of vertex set Q the running time is in $O(|E| \cdot dk_Q + |V| \cdot em_Q)$, where $dk_Q$ and $em_Q$ are times needed to perform decrease key and extract minimum operations in set Q, respectively.

The simplest implementation of the Dijkstra‘s algorithm stores vertices of set Q in an ordinary linked list or array, and extract minimum from Q is simply a linear search through all vertices in Q. In this case, the running time is $O(|E| + |V|^2) = O(|V|^2)$.

For sparse graphs, that is, graphs with far fewer than $O(|V|^2)$ edges, Dijkstra‘s algorithm can be implemented more efficiently by storing the graph in the form of adjacency lists and using a self-balancing binary search tree, binary heap, pairing heap, or Fibonacci heap as a priority queue to implement extracting minimum efficiently. With a self-balancing binary search tree or binary heap, the algorithm requires $\Theta((|E| + |V|) \log |V|)$ time (which is dominated by $\Theta( | E | \log | V | )$, assuming the graph is connected). To avoid $O(|V|)$ look-up in decrease-key step on a vanilla binary heap, it is necessary to maintain a supplementary index mapping each vertex to the heap‘s index (and keep it up to date as priority queue Q changes), making it take only $O(\log|V|)$ time instead. The Fibonacci heap improves this to $O(|E| + |V| \log|V|)$.

  1 #include <iostream>  2 #include <string>  3 #include <sstream>  4 #include <fstream>  5 #include <vector>  6 #include <stdlib.h>  7 #include <string.h>  8 #include <queue>  9 #include <map> 10 #define MAX 10000 11 using namespace std; 12  13 struct Node { 14     int dist; 15     int index; 16     Node() {} 17     Node(int i, int d) : index(i), dist(d) {} 18 }; 19  20 ostream &operator<<(ostream& os, Node& node) { 21     os << node.index << "(" << node.dist << ") ";  22     return os; 23 } 24  25 class Dijkstra{ 26     public: 27         Dijkstra():n(0), capacity(100) { 28             this->arr = new Node[capacity]; 29         } 30  31         ~Dijkstra() { 32             delete[] arr; 33         } 34  35         void insert(Node v) { 36             if (n >= capacity) { 37                 Node* tmp = new Node[capacity << 1]; 38                 memcpy(tmp, arr, sizeof(Node) * capacity); 39                 capacity <<= 1; 40             } 41             keyMap[v.index] = n; 42             arr[n++] = v; 43             shiftUp(n - 1); 44         } 45  46         void shiftDown(int st, int ed) { 47             Node tmp = arr[st]; 48             while (st < ed) { 49                 int next = -1; 50                 int left = st * 2 + 1; // left child node  51                 if (left < ed) next = left; 52                 else break; 53                 int right = st * 2 + 2; 54                 if (right < ed && arr[right].dist < arr[next].dist) next = right; 55                 if (arr[next].dist < arr[st].dist) { 56                     keyMap[arr[next].index] = st; 57                     arr[st] = arr[next]; 58                     st = next; 59                 } else break; 60             } 61             keyMap[tmp.index] = st; 62             arr[st] = tmp; 63         } 64  65         void shiftUp(int ed) { 66             Node tmp = arr[ed]; 67             while (ed > 0) { 68                 int parent = (ed - 1) / 2; 69                 if (arr[ed].dist < arr[parent].dist) { 70                     keyMap[arr[parent].index] = ed; 71                     arr[ed] = arr[parent]; 72                     ed = parent; 73                 } else break; 74             } 75             keyMap[tmp.index] = ed; 76             arr[ed] = tmp; 77         } 78  79         void update(int pos, int v) { 80             if (pos >= n) { 81                 arr[pos].dist = v; 82             } else if (arr[pos].dist < v) { 83                 arr[pos].dist = v; 84                 shiftDown(pos, n); 85             } else { 86                 arr[pos].dist = v; 87                 shiftUp(pos); 88             } 89         } 90  91         bool empty() const { 92             return n <= 0; 93         } 94  95         Node top() { 96             if (empty()) return Node(); 97             return arr[0]; 98         } 99 100         void pop() {101             if (empty()) return;102             keyMap[arr[n - 1].index] = 0;103             keyMap[arr[0].index] = n - 1;104             swap(arr[0], arr[n - 1]);105             shiftDown(0, --n);106         }107 108         void load(string filename) {109             ifstream in(filename.c_str());110             string line;111             getline(in, line);112             int n = atoi(line.c_str());113 114             while (adjList.size() < n && getline(in, line)) {115                 vector<int> neigs;116                 stringstream ss(line);117                 int v = 0;118                 while (ss >> v) {119                     neigs.push_back(v - 1);120                 }121                 adjList.push_back(neigs);122             }123 124             while (getline(in, line)) {125                 vector<int> ws;126                 stringstream ss(line);127                 int w = 0;128                 while (ss >> w) {129                     ws.push_back(w);130                 }131                 weights.push_back(ws);132             }133 134             for (int i = 0; i < adjList.size(); ++i) {135                 for (int j = 0; j < adjList[i].size(); ++j) {136                     cout << adjList[i][j] << "(" << weights[i][j] << ") ";137                 }138                 cout << endl;139             }140         }141 142         // dijstra using binary heap, O((|V|+|E|)lg|V|)143         int run() {144             if (adjList.empty()) return 0;145             insert(Node(0, 0));146             for (int i = 1; i < adjList.size(); ++i) {147                 insert(Node(i, MAX));148             }149 150             while (!empty()) {    151                 Node nearest = top(); 152                 pop(); // O(|V|lg|V|)153 154                 for (int j = 0; j < adjList[nearest.index].size(); ++j) {155                     int d = nearest.dist + weights[nearest.index][j];156                     int neig = adjList[nearest.index][j];157                     if (d < arr[keyMap[neig]].dist) update(keyMap[neig], d); // O(|E|lg|V|)158                 }159             }160 161             for (int i = 0; i < adjList.size(); ++i) {162                 cout << arr[i] << " ";163             }164             cout << endl;165             return 0;166         }167 168     private:169         Node* arr;170         int n;171         int capacity;172         map<int, int> keyMap; // from graph index to arr index173         vector<vector<int> > adjList, weights;174 };175 176 int main()177 {178     Dijkstra dij;179     dij.load("input.txt");180     dij.run();181     return 0;182 }

input.txt:

6 2 3 61 3 41 2 4 62 3 54 61 3 57 9 147 10 159 10 11 215 11 66 914 2 9

每一行是顶点个数;

前几行是邻接列表;后几行是对应的边的权重;