数据结构与算法——最短路径Dijkstra算法的C++实现
来源:互联网 发布:node v0.12.2 x64.msi 编辑:程序博客网 时间:2024/05/16 18:44
之前的讨论了无权图的最短路径算法。数据结构与算法——无权最短路径算法的C++实现
如果是加权图,那么问题就变得困难了,不过仍然可以采用无权情况的想法。
我们仍然保留之前的信息。因此,每个顶点会被标记为known或unknown,每个顶点保留一个尝试性的距离dv(这个距离是只使用一些known顶点作为中间顶点从s到v的最短路径的长),每个顶点还保留字段pv,该字段是记录引起dv变化的最后的顶点。
图顶点信息的数据结构:
//保存每个顶点信息的数据结构struct GraphNode{ bool known;//当前顶点距离起点的距离是否确定 int dist;//当前顶点到起点的最短距离 int path;//当前顶点距离起点的最短路径的前一个顶点};
Dijkstra算法简介:
解决单源最短路径问题的一般方法叫做Dijkstra算法。这个算法是贪心算法最好的例子。
贪心算法一般分阶段求解问题,在每个阶段它都把出现的东西当作是最好的去处理。
与无权最短路径算法一样,Dijkstra算法按阶段进行。在每个阶段,Dijkstra算法选择一个顶点v,它在所有的unknown顶点中具有最小的dv,同时算法声明从s到v的最短路径是known的。其它阶段由顶点dv的更新工作成。
主要思想就是根据已经确定了的点的距离,来确定该点相邻顶点的距离,不断的向外散射,直到所以的点的到起点的最短距离确定为止。
下面是Dijkstra算法具体步骤图示:
假设源点s=v1,下面是求s到其它点的最短距离。
第一步:初始化顶点信息
第二步:
顶点v1就是顶点s,那么距离顶点v1路径长为0,将顶点v1字段的known设为true。
与s相邻的点为v2,v4。v1到v2的距离为4,v1到v4的距离为1。并更新v2和v4的距离。
p2 = v1; p4 = v1;
第三步:
寻找unknown的顶点中距离最短的顶点,并将该顶点标记为known。所以将v4标记为known。
然后,再根据顶点v4的dv值更新与v4相邻的所有点(v3,v6,v7,v5)的距离。
d4+d43 = 1+2 < d3,所以d3 = 3;p3 = v4;
d4+d46 = 1+8 < d6,所以d6 = 9;p6 = v4;
d4+d47 = 1+4 < d7,所以d7 = 5;p7 = v4;
d4+d45 = 1+2 < d5,所以d5 = 3;p5 = v4;
第四步:
执行第三步,寻找unknown的顶点中距离最短的顶点,并将该顶点标记为known。所以将v2标记为known。
然后,再根据顶点v2的dv值更新与v2相邻的所有点(v4,v5)的距离。因为v4已经确定了,就不用更新了。因为d2+d25 = 2 + 10 > d5,d5的值为3。所以不需要更新d5。
第五步:
执行第三步,寻找unknown的顶点中距离最短的顶点,并将该顶点标记为known。所以将v5标记为known。
然后,再根据顶点v5的dv值更新与v5相邻的所有点(v7)的距离。因为d5+d57 = 3+6>d7,所以d7不用更新。
第六步:
执行第三步,寻找unknown的顶点中距离最短的顶点,并将该顶点标记为known。所以将v3标记为known。
然后,再根据顶点v3的dv值更新与v3相邻的所有点(v1,v6)的距离。因为v1是known的,所以d1不用更新。d3+d36 = 3+5 < d6,所以d6 = d3+d36 = 8; p6 = v3;
第七步:
执行第三步,寻找unknown的顶点中距离最短的顶点,并将该顶点标记为known。所以将v7标记为known。
然后,再根据顶点v7的dv值更新与v7相邻的所有点(v6)的距离。因为d7+d76 = 5+1<d6,所以d6=d7+d76 = 6; p6 = v7;
第八步:
执行第三步,寻找unknown的顶点中距离最短的顶点,并将该顶点标记为known。所以将v6标记为known。
然后,再根据顶点v6的dv值更新与v6相邻的所有点的距离。结果没有v6指向的其它顶点。
第九步:
执行第三步,寻找unknown的顶点中距离最短的顶点,并将该顶点标记为known。结果没有找到满足条件的顶点,表明此时已经确定了所有顶点的距离,则退出算法。
Dijkstra算法的基本步骤:
1、初始化顶点信息;v.known = flase;v.dist = INFINITY;v.path = 0;
2、对起点s的dist字段设为0;s.dist = 0;
3、从所有顶点中找到dist最小的并且known为false的顶点v。然后将该顶点v的known置为true;
然后更新与顶点v相邻的所有其它known为false的顶点w的dist和path的值。
如果v.dist+distance(v,w) < w.dist;则更新w.dist = v.dist + distance(v, w);w.path=v;
4、循环执行第3步,直到从所有顶点中找不到known为false的顶点v为止,找不到合适的顶点的时候则退出算法。
Dijkstra算法的伪代码:
void Graph::dijkstra(Vertex s){ //初始化顶点信息 for each Vertex v { v.known = false; v.dist = INFINITY; v.path = 0; } //起点s的dist设为0 s.dist = 0; //循环执行第3步 for(; ;) { //从所有顶点中找到dist最小的并且known为false的顶点v Vertex v = unknown smallest distance vertex; //如果没有找到满足条件的v,则退出算法(此时所有顶点已经全部确定了) if(v == NOT_A_VERTEX) break; //将该顶点v的known置为true v.known = true; //更新与顶点v相邻的所有其它known为false的顶点w的dist和path的值 for each Vertex w adjacent to v { if(!w.known) { //更新w.dist if(v.dist+distance(v,w) < w.dist) { w.dist = v.dist + distance(v,w); w.path = v; } } } }}
Dijkstra算法的代码:
/************************************************** 函数名称: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; } } } }}
图类的接口:
/******************************************************** 类名称: 邻接表图********************************************************/ 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);};
测试主函数:
int main(int argc, char *argv[]){ char *topo[5000]; int edge_num; char *demand; int demand_num; char *topo_file = argv[1]; edge_num = read_file(topo, 5000, topo_file); if (edge_num == 0) { printf("Please input valid topo file.\n"); return -1; } int src; cout << "输入求最短路径的起点:"; cin >> src; Graph G(topo, edge_num); G.print(); cout << "Dijkstra: " << endl; G.dijkstra(src); G.printShorestPath(); release_buff(topo, edge_num);return 0;}
测试的图的数据:
1,1,2,22,1,4,13,2,4,34,2,5,105,3,1,46,3,6,57,4,3,28,4,6,89,4,5,210,4,7,411,5,7,612,7,6,1
图类的源代码:
#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
测试函数的源代码:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <time.h>#include <sys/timeb.h>#include <errno.h>#include <unistd.h>#include <signal.h>#include <stdio.h>#include "graphDijkstra.h"#define MAX_LINE_LEN 4000int read_file(char ** const buff, const unsigned int spec, const char * const filename);void release_buff(char ** const buff, const int valid_item_num);int main(int argc, char *argv[]){ char *topo[5000]; int edge_num; char *demand; int demand_num; char *topo_file = argv[1]; edge_num = read_file(topo, 5000, topo_file); if (edge_num == 0) { printf("Please input valid topo file.\n"); return -1; } int src; cout << "输入求最短路径的起点:"; cin >> src; Graph G(topo, edge_num); G.print(); cout << "Dijkstra: " << endl; G.dijkstra(src); G.printShorestPath(); release_buff(topo, edge_num);return 0;}/***************************************************************** 函数名称:read_file* 功能描述: 读取文件中的图的数据信息* 参数列表: buff是将文件读取的图信息保存到buff指向的二维数组中 * spec是文件中图最大允许的边的个数* filename是要打开的图文件* 返回结果:无*****************************************************************/int read_file(char ** const buff, const unsigned int spec, const char * const filename){ FILE *fp = fopen(filename, "r"); if (fp == NULL) { printf("Fail to open file %s, %s.\n", filename, strerror(errno)); return 0; } printf("Open file %s OK.\n", filename); char line[MAX_LINE_LEN + 2]; unsigned int cnt = 0; while ((cnt < spec) && !feof(fp)) { line[0] = 0; fgets(line, MAX_LINE_LEN + 2, fp); if (line[0] == 0) continue; buff[cnt] = (char *)malloc(MAX_LINE_LEN + 2); strncpy(buff[cnt], line, MAX_LINE_LEN + 2 - 1); buff[cnt][4001] = 0; cnt++; } fclose(fp); printf("There are %d lines in file %s.\n", cnt, filename); return cnt;}/***************************************************************** 函数名称:release_buff* 功能描述: 释放刚才读取的文件中的图的数据信息* 参数列表: buff是指向文件读取的图信息* valid_item_num是指图中边的个数* 返回结果:void*****************************************************************/void release_buff(char ** const buff, const int valid_item_num){ for (int i = 0; i < valid_item_num; i++) free(buff[i]);}
运行结果:
2 0
- 数据结构与算法——最短路径Dijkstra算法的C++实现
- 数据结构与算法——最短路径Dijkstra算法的C++实现
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现代码(C/C++)
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
- 数据结构-最短路径—Dijkstra算法和Floyd算法
- dijkstra最短路径算法C实现
- 最短路径算法—Dijkstra(迪杰斯特拉)算法的实现(C++)
- 最短路径算法—Dijkstra算法与Floyd算法
- [数据结构与算法]最短路径—Dijkstra算法和Floyd算法
- 最短路径之dijkstra算法的C语言实现
- 最短路径Dijkstra算法的C语言实现
- 判断字符串中含有某字符串
- zoj 2886
- 彩色RGB图像转为灰度图像
- Android下拉控件(Spinner)的基础使用
- 初识RecyclerView(三)
- 数据结构与算法——最短路径Dijkstra算法的C++实现
- Go 性能优化技巧 3/10
- 使用OpenCV进行图像创建、保存和复制
- Laravel5 安装
- Listview中显示不同的视图布局
- 安装win7 win10 双系统
- 直方图内矩形面积
- Maven学习总结(二)——Maven项目构建过程练习
- 《java入门第一季》之面向对象(构造方法)