標籤:資料結構 dijkstra 單源最短路徑 演算法
Dijkstra演算法
單源最短路徑
給定一帶權圖,圖中每條邊的權值是非負的,代表著兩頂點之間的距離。指定圖中的一頂點為源點,找出源點到其它頂點的最短路徑和其長度的問題,即是單源最短路徑問題。
Dijkstra演算法
求解單源最短路徑問題的常用方法是Dijkstra(迪傑斯特拉)演算法。該演算法使用的是貪心策略:每次都找出剩餘頂點中與源點距離最近的一個頂點。
演算法思想
帶權圖G=<V,E>,令S為已確定了最短路徑頂點的集合,則可用V-S表示剩餘未確定最短路徑頂點的集合。假設V0是源點,則初始 S={V0}。用數組Distance表示源點V0到其餘頂點的路徑長度,用數組pre[i]表示最短路徑序列上頂點i的前一個頂點。初始時,pre[i]都是源點的下標。接下來需重複兩個步驟:
- 從當前Distance[i]找出最小的一個,記錄其下標v=i,源點V0到頂點Vv的最短路徑即已確定,把Vv加入S。
- 更新源點到剩餘頂點的最短路徑長度。更新方法是:以上一步的頂點Vv為中間點,若Distance[v]+weight(v,i)<Distance[i],則修改值:pre[i]=v;Distance[i]=Distance[v]+weight(v,i);
重複以上兩個步驟,直至所有頂點的最短路徑都已找到。
需要指出,Dijkstra演算法求解的不僅是有向圖,無向圖也是可以的。下面給出一個完整的有向帶權圖的執行個體:
執行個體
有向帶權圖
Dijkstra演算法的求解過程
其中,INF是infinity無窮大的意思。
代碼
類定義
#include<iostream> #include<iomanip>#include<stack>using namespace std;#define MAXWEIGHT 100#ifdef INFINITY#undef INFINITY#endif#define INFINITY 1000class Graph{private://頂點數 int numV;//邊數 int numE;//鄰接矩陣 int **matrix;public:Graph(int numV);//建圖 void createGraph(int numE);//析構方法 ~Graph();//迪傑斯特拉演算法void Dijkstra(int);//列印鄰接矩陣 void printAdjacentMatrix();//檢查輸入 bool check(int, int, int);};類實現
//建構函式,指定頂點數目Graph::Graph(int numV){//對輸入的頂點數進行檢測while (numV <= 0){cout << "頂點數有誤!重新輸入 ";cin >> numV;}this->numV = numV;//構建鄰接矩陣,並初始化matrix = new int*[numV];int i, j;for (i = 0; i < numV; i++)matrix[i] = new int[numV];for (i = 0; i < numV; i++)for (j = 0; j < numV; j++){if (i == j)matrix[i][i] = 0;elsematrix[i][j] = INFINITY;}}void Graph::createGraph(int numE){/*對輸入的邊數做檢測一個numV個頂點的有向圖,最多有numV*(numV - 1)條邊*/while (numE < 0 || numE > numV*(numV - 1)){cout << "邊數有問題!重新輸入 ";cin >> numE;}this->numE = numE;int tail, head, weight, i;i = 0;cout << "輸入每條邊的起點(弧尾)、終點(弧頭)和權值" << endl;while (i < numE){cin >> tail >> head >> weight;while (!check(tail, head, weight)){cout << "輸入的邊不正確!請重新輸入 " << endl;cin >> tail >> head >> weight;}matrix[tail][head] = weight;i++;}}Graph::~Graph(){int i;for (i = 0; i < numV; i++)delete[] matrix[i];delete[]matrix;}/*迪傑斯特拉演算法求指定頂點vertex到其它頂點的最短路徑不僅要得出最短路徑長度,也要得到其序列*/void Graph::Dijkstra(int vertex){int i;//最短路徑序列中每個頂點的直接前驅int *pre = new int[numV];for (i = 0; i < numV; i++)pre[i] = vertex;//頂點vertex到各個頂點的路徑長度int *Distance = new int[numV];//初始化路徑長度for (i = 0; i < numV; i++)Distance[i] = matrix[vertex][i];//標記各個頂點最短路徑找到與否bool *find = new bool[numV];memset(find, 0, numV);find[vertex] = true;int d, v, count;count = 1, v = vertex;while (count < numV){d = INFINITY;//確定一個最短距離for (i = 0; i < numV; i++){if (!find[i] && Distance[i] < d){d = Distance[i];v = i;}}find[v] = true;//更新剩餘頂點的前驅和最短距離for (i = 0; i < numV; i++){if (!find[i]){d = Distance[v] + matrix[v][i];if (d < Distance[i]){pre[i] = v;Distance[i] = d;}}}count++;}//列印最短路徑序列和其長度stack<int> s;for (i = 0; i < numV; i++){if (Distance[i] == 0);else if (Distance[i] == INFINITY)cout << "頂點 " << vertex <<" 到頂點 " << i <<" 無路徑!" << endl;else{cout << "頂點 " << vertex << " 到頂點 " << i << " 最短路徑長度是 " << Distance[i] << " ,其序列是...";v = i;s.push(v);do{v = pre[v];s.push(v);} while (v!=vertex);//列印最短路徑序列while (!s.empty()){cout << setw(3) << s.top();s.pop();}cout << endl;}}cout << endl;delete[]find;delete[]pre;delete[]Distance;}//列印鄰接矩陣 void Graph::printAdjacentMatrix(){int i, j;cout.setf(ios::left);cout << setw(7) << " ";for (i = 0; i < numV; i++)cout << setw(7) << i;cout << endl;for (i = 0; i < numV; i++){cout << setw(7) << i;for (j = 0; j < numV; j++)cout << setw(7) << matrix[i][j];cout << endl;}}bool Graph::check(int tail, int head, int weight){if (tail < 0 || tail >= numV || head < 0 || head >= numV|| weight <= 0 || weight >= MAXWEIGHT)return false;return true;}主函數
int main(){cout << "******Dijkstra***by David***" << endl;int numV, numE;cout << "建圖..." << endl;cout << "輸入頂點數 ";cin >> numV;Graph graph(numV);cout << "輸入邊數 ";cin >> numE;graph.createGraph(numE);cout << endl << "Dijkstra..." << endl;for (int i = 0; i < numV; i++)graph.Dijkstra(i);system("pause");return 0;}運行
完整代碼下載:Dijkstra演算法
轉載請註明出處,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/38360337
若有所協助,頂一個哦!
專欄目錄: