有向加权图的最短路径算法-Dijkstra

1 有向加权图的数据结构如下

4 5 0.35
5 4 0.35
4 7 0.37
5 7 0.28
7 5 0.28
5 1 0.32
0 4 0.38
0 2 0.26
7 3 0.39
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93

2 实现的C++代码如下,可以由其中的某个顶点起,找到可达的所有最短路径

Graph.h头文件,描述了加权有向边,加权有向图,和最短路径算法

/*
 * Graph.h
 *
 *  Created on: 2014年5月17日
 *      Author: zhongchao
 */

#ifndef _GRAPH_
#define _GRAPH_
#include <fstream>
#include <iostream>
#include <ext/hash_map>
#include <hash_set>
#include <map>
#include<limits>
#include <stdio.h>
#include <string.h>

using namespace std;
using namespace __gnu_cxx;

/*
 * 有向图算法:最短路径
 */
//----------------------带权重的有向边--------------------
class DirWeightEdge
{
private:
		int _from; //起点
		int _to;       //终点
		double _weight; //权重
public:
		DirWeightEdge();
		DirWeightEdge(int a, int b, double c);
		~DirWeightEdge();
		int from();
		int to();
		double weight();
};
//---------------------------------------------------------------------

//---------------------带权重的有向图----------------------
class DirWeightGraph
{
private:
		hash_map<int, vector<DirWeightEdge*> > adj; //邻接表
		hash_set<int> nodes;
		int _eNum; //边的个数
		int _vNum; //节点个数

public:
		DirWeightGraph(string path);
		~DirWeightGraph();
		void addEdge(int f,  int t, double w);
		vector<DirWeightEdge*> getAdj(int n);
		int e();
		int v();
		vector<DirWeightEdge*> edges(int node);
		hash_set<int> getNodes();
};
//--------------------------------最短路径算法-----------------------------
class Dijkstra
{
private:
		bool*  mark;   //标记被访问过的节点
		double* distTo; //从起点开始到某个终点的距离
		DirWeightEdge**  edgeTo; //存储最短路径的中的边
		map<double, int> pq;
		hash_set<int> pqMark;
		int startNode;
		int nodeNum;
public:
		Dijkstra(DirWeightGraph* graph, int node);
		~Dijkstra();
		void visit(DirWeightGraph* graph, int v);
		bool hasPathTo(int n);
		vector<DirWeightEdge*> pathTo(int n);
		void allPath(DirWeightGraph* graph, int n);
		void printPath(vector<DirWeightEdge*> & path);
};
//----------------------------------------------------------------------
#endif /* _GRAPH_*/

头文件Graph.h对应的源文件实现

/*
 * Graph.cpp
 *
 *  Created on: 2014年5月17日
 *      Author: zhongchao
 */
#include "Graph.h"
DirWeightEdge::DirWeightEdge(int a, int b, double c)
{
		this->_from = a;
		this->_to = b;
		this->_weight = c;
}
DirWeightEdge::	~DirWeightEdge()
{
}
int DirWeightEdge::from()
{
		return _from;
}

int DirWeightEdge::to()
{
		return _to;
}

double DirWeightEdge::weight()
{
		return _weight;
}

//---------------------------------有向图---------------------------------
hash_set<int> DirWeightGraph::getNodes()
{
		return nodes;
}
void DirWeightGraph::addEdge(int f,  int t,  double w)
{
		DirWeightEdge* dirWeightEdge = new DirWeightEdge(f, t, w);
		if(adj.find(f) != adj.end())
		{
				adj.find(f)->second.push_back(dirWeightEdge);
		}
		else
		{
				vector<DirWeightEdge*> edges;
				edges.push_back(dirWeightEdge);
				adj.insert(pair<int, vector<DirWeightEdge*> >(f, edges));
		}
}
DirWeightGraph::DirWeightGraph(string path)
{
		this->_eNum = 0;
		this->_vNum = 0;
		ifstream reader(path.c_str(),  ios_base::in);
		if(reader.is_open())
		{
				while(!reader.eof())
				{
						int f, t;
						double w;
						reader>>f>>t>>w;
						if(reader.fail())
								break;
						//cout<<f<<" "<<t<<" "<<w<<endl;
						nodes.insert(f);
						nodes.insert(t);
						addEdge(f, t, w);
						_eNum++;   //边的条数
				}
		}
}

int DirWeightGraph::e()
{
		return _eNum;
}

int DirWeightGraph::v()
{
		return nodes.size();
}
vector<DirWeightEdge*> DirWeightGraph::getAdj(int n)
{
		return adj.find(n)->second;
}
DirWeightGraph::~DirWeightGraph()
{
			for(hash_map<int, vector<DirWeightEdge*> >::iterator it = adj.begin(); it != adj.end(); it++)
			{
					for(vector<DirWeightEdge*>::iterator it1 = it->second.begin(); it1 != it->second.end(); it1++)
					{
							delete *it1;
					}
			}
}
//Dijkstra最短路径算法
Dijkstra::Dijkstra(DirWeightGraph* graph, int v)
{
		mark = new bool[graph->v()];
		distTo = new double[graph->v()];
		edgeTo = new DirWeightEdge* [graph->v()];
		startNode = v;
		nodeNum = graph->v();
		//edgeTo = new vector<DirWeightEdge*>();
		//pq = new map<double, int>();

		for(int i = 0; i < graph->v(); i++)
		{
				distTo[i] = numeric_limits<double>::max(); //无穷大
				mark[i] = false;
		}
		distTo[v] = 0.0;
		mark[v] = true;
		pq.insert(pair<double, int>(0.0, v));
		pqMark.insert(0);
		while(pq.size() != 0)
		{
				int v = pq.begin()->second;
				pq.erase(pq.begin());
				visit(graph, v);
		}

}

void Dijkstra::visit(DirWeightGraph* graph, int v)
{
		vector<DirWeightEdge*> edges = graph->getAdj(v);
		for(vector<DirWeightEdge*>::iterator it = edges.begin(); it != edges.end(); it++)
		{
				int f = (*it)->from();
				int t = (*it)->to();
				double w = (*it)->weight();
				if(distTo[t] > distTo[f] + w)
				{
						mark[t] =true;
						distTo[t] = distTo[f] + w;
						edgeTo[t] = *it;
						if(pqMark.find(t) == pqMark.end())
						{
								pq.insert(pair<double, int>( distTo[t], t));
								pqMark.insert(t);
						}
						else
						{
								edgeTo[t] = *it;
								for(map<double, int>::iterator it = pq.begin(); it != pq.end(); it++)
								{
										if(it->second == t)
										{
												pq.erase(it);
												pq.insert(pair<double, int>(distTo[t], t ));
										}
								}
						}
				}
		}
}
bool Dijkstra::hasPathTo(int n)
{
		return mark[n];
}

vector<DirWeightEdge*> Dijkstra::pathTo(int n)
{
	    vector<DirWeightEdge*> paths;
 		if(hasPathTo(n))
		{
 				DirWeightEdge* e = edgeTo[n];
 				int f = e->from();
 				paths.push_back(e);
 				while(f != startNode)
 				{
 						e = edgeTo[f];
 						f = e->from();
 						paths.push_back(e);
 				}
		}
 		return paths;
}
void Dijkstra::printPath(vector<DirWeightEdge*>& path)
{
		vector<DirWeightEdge*>::reverse_iterator rit;
		for(rit = path.rbegin(); rit != path.rend(); rit++)
		{
				cout<<(*rit)->from()<<"->";
		}
		cout<<(*path.begin())->to();
}
void Dijkstra::allPath(DirWeightGraph*  graph, int node)
{
		hash_set<int> nodes = graph->getNodes();
		for(hash_set<int>::iterator it = nodes.begin(); it != nodes.end(); it++)
		{
				int n = *it;
				if (n == node)
						continue;
				if(hasPathTo(n))
				{
						vector<DirWeightEdge*> paths = pathTo(n);
						printPath(paths);
						cout<<": weight=" <<distTo[n]<<endl;
				}
		}
}
Dijkstra::~Dijkstra()
{
		delete[] mark;
		delete[] distTo;
		for(int i = 0; i < nodeNum; i++)
		{
				delete edgeTo[i];
		}
		delete[] edgeTo;
}

测试程序如下

#include "Graph.h"
int main(int argc, char** argv)
{
	//最短路径算法
	string path("tinyEWD.txt"); //<span style="font-family: Arial, Helvetica, sans-serif;">tinyEWD.txt 存储图的文件</span>
	DirWeightGraph* dirWeightGraph = new DirWeightGraph(path); //实例化有向加权图对象
	int n = 1;   //最短路径的起点
	Dijkstra* dijkstra = new Dijkstra(dirWeightGraph, n); //实例化最短路径对象
	dijkstra->allPath(dirWeightGraph, n);   //打印可达点的路径
	return 1;
}

从起点1开始的所有可达点的最短路径如下

1->3->6->0: weight=1.39
1->3->6->2: weight=1.21
1->3: weight=0.29
1->3->6->4: weight=1.74
1->3->6->2->7->5: weight=1.83
1->3->6: weight=0.81
1->3->6->2->7: weight=1.55

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/zc02051126/article/details/27962697
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞