資料結構與演算法——最短路徑Dijkstra演算法的C++實現
阿新 • • 發佈:2018-12-30
#ifndef GRAPH_H #define GRAPH_H #include <list> #include <iostream> #include <vector> #include <stdlib.h> #include <string.h> #include <algorithm> #include <iterator> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <signal.h> #include <queue> using namespace std; #define MAX_VERTEX_NUM 600 #define INFINITY 1000000//將INFINITY定義為無窮大的值 //儲存每個頂點資訊的資料結構 struct GraphNode{ bool known;//當前頂點距離起點的距離是否確定 int dist;//當前頂點到起點的最短距離 int path;//當前頂點距離起點的最短路徑的前一個頂點 }; //圖節點資訊 typedef struct Node{ int edge_num;//邊號 int src;//源點 int vertex;//自身 int weight;//邊的權重 }Node; /******************************************************* * 類名稱: 鄰接表圖 ********************************************************/ class Graph{ private: int edge_num;//圖邊的個數 int vertex_num;//圖的頂點數目 list<Node> * graph_list;//鄰接表 vector<GraphNode> nodeArr;//儲存每個頂點資訊的陣列 public: Graph(){} Graph(char* graph[], int edgenum); ~Graph(); void print(); void dijkstra(int src); void printShorestPath(); private: vector<int> get_graph_value(char* graph[], int columns); void addEdge(char* graph[], int columns); }; /************************************************* * 函式名稱:dijkstra(int src) * 功能描述:求無權圖的任意點到其它頂點的距離 * 引數列表:src是起點 * 返回結果:void *************************************************/ void Graph::dijkstra(int src) { //初始化頂點資訊 for(int i = 0; i < vertex_num; ++i){ nodeArr[i].known = false; nodeArr[i].dist = INFINITY; nodeArr[i].path = 0; } //重要的一步,開啟演算法的關鍵一步 nodeArr[src].dist = 0; for(; ;){ //找到unknown的dist最小的頂點 int v = 0; int max = INFINITY; for(int i = 0; i < vertex_num; ++i){ if(!nodeArr[i].known && (max > nodeArr[i].dist)){ max = nodeArr[i].dist; v = i; } } //沒有找到滿足條件的頂點,退出演算法 if(max == INFINITY) break; nodeArr[v].known = true; //更新與v相鄰所有頂點w的dist,path for(list<Node>::iterator it = graph_list[v].begin(); it != graph_list[v].end(); ++it){ if(!nodeArr[(*it).vertex].known){ if(nodeArr[v].dist + (*it).weight < nodeArr[(*it).vertex].dist){ nodeArr[(*it).vertex].dist = nodeArr[v].dist + (*it).weight; nodeArr[(*it).vertex].path = v; } } } } } /************************************************* * 函式名稱:printShorestPath() * 功能描述:將獲得的src頂點到其它頂點的最短路徑輸出 * 引數列表:無 * 返回結果:無 *************************************************/ void Graph::printShorestPath() { cout << "頂點\t" << "known\t" << "dist\t" << "path" << endl; for(int i = 0; i < vertex_num; ++i){ if(nodeArr[i].known) cout << i << "\t" << nodeArr[i].known << "\t" << nodeArr[i].dist << "\t" << nodeArr[i].path << endl; } } /************************************************* * 函式名稱:print * 功能描述:將圖的資訊以鄰接表的形式輸出到標準輸出 * 引數列表:無 * 返回結果:無 *************************************************/ void Graph::print() { cout << "******************************************************************" << endl; //for(int i = 0 ; i < MAX_VERTEX_NUM; ++i){ for(int i = 0 ; i < vertex_num; ++i){ if(graph_list[i].begin() != graph_list[i].end()){ cout << i << "-->"; for(list<Node>::iterator it = graph_list[i].begin(); it != graph_list[i].end(); ++it){ cout << (*it).vertex << "(邊號:" << (*it).edge_num << ",權重:" << (*it).weight << ")-->"; } cout << "NULL" << endl; } } cout << "******************************************************************" << endl; } /************************************************* * 函式名稱:get_graph_value * 功能描述:將圖的每一條邊的資訊儲存到一個數組中 * 引數列表: graph:指向圖資訊的二維陣列 columns:圖的第幾條邊 * 返回結果:無 *************************************************/ vector<int> Graph::get_graph_value(char* graph[], int columns) { vector<int> v; char buff[20]; int i = 0, j = 0, val; memset(buff, 0, 20); while((graph[columns][i] != '\n') && (graph[columns][i] != '\0')){ if(graph[columns][i] != ','){ buff[j] = graph[columns][i]; j++; } else{ j = 0; val = atoi(buff); v.push_back(val); memset(buff, 0, 20); } i++; } val = atoi(buff); v.push_back(val); return v; } /************************************************* * 函式名稱:addEdge * 功能描述:將圖的每一條邊的資訊加入圖的鄰接表中 * 引數列表:graph:指向圖資訊的二維陣列 columns:圖的第幾條邊 * 返回結果:無 *************************************************/ void Graph::addEdge(char* graph[], int columns) { Node node; vector<int> v = get_graph_value(graph, columns); node.edge_num = v[0]; node.src = v[1]; node.vertex = v[2]; node.weight = v[3]; //根據頂點的標號,求的總的頂點數目 if(node.vertex > vertex_num) vertex_num = node.vertex; //要考慮重複的邊,但是邊的權重不一樣 for(list<Node>::iterator it = graph_list[node.src].begin(); it != graph_list[node.src].end(); ++it){ if((*it).vertex == node.vertex){ if((*it).weight > node.weight){ (*it).weight = node.weight; } return; } } graph_list[node.src].push_back(node); } /************************************************* * 函式名稱:建構函式 * 功能描述:以鄰接表的形式儲存圖的資訊,並儲存必須經過的頂點 * 引數列表:graph:指向圖資訊的二維陣列 edgenum:圖的邊的個數 * 返回結果:無 *************************************************/ Graph::Graph(char* graph[], int edgenum):nodeArr(MAX_VERTEX_NUM) { edge_num = edgenum; vertex_num = 0; graph_list = new list<Node>[MAX_VERTEX_NUM+1]; for(int i = 0; i < edgenum; ++i){ addEdge(graph, i); } //對頂點資訊進行初始化 for(int i = 0; i < MAX_VERTEX_NUM; ++i){ nodeArr[i].known = false; nodeArr[i].dist = INFINITY; nodeArr[i].path = -1;//如果為-1,表示沒有該點,配合dijkstra演算法使用 } vertex_num++; } /************************************************* * 函式名稱:解構函式 * 功能描述:釋放動態分配的記憶體 * 引數列表:無 * 返回結果:無 *************************************************/ Graph::~Graph() { delete[] graph_list; } #endif