Dijkstra算法

原创 2015年11月18日 18:13:44

        Dijkstra算法(迪杰斯特拉算法)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。(迪杰斯特拉算法-百度百科


Dijkstra算法运行动画过程



源代码

#include <iostream>
#include <vector>
using namespace std;

/// 加权有向边的数据结构
class DirectedEdge
{
public:
	DirectedEdge(size_t _v, size_t _w, double _weight) : v(_v), w(_w), weights(_weight) { }
	DirectedEdge() : v(0), w(0), weights(DBL_MAX) { } // 默认构造函数

	size_t from() const { return v; }
	size_t to()   const { return w; }
	double weight() const { return weights; }
	void print() const { cout << "(" << v << "->" << w << ": " << weights << ") "; }

private:
	size_t v, w;
	double weights;
};

/// 加权有向图的数据结构
class EdgeWeightDigraph
{
public:
	EdgeWeightDigraph(size_t v) : vertax(v), edge(0), arr(v) {}

	void addEdge(const DirectedEdge &e);

	vector<DirectedEdge> adj(size_t v) const;
	vector<DirectedEdge> edges() const;
	size_t getVertax() const { return vertax; }
	size_t getEdge() const { return edge; }
	size_t getArrSize() const { return arr.size(); }

	void printAdj(size_t v) const;
	void printGraph() const;

private:
	size_t vertax, edge;
	vector<vector<DirectedEdge>> arr;
};

/// 最短路径的加权有向图Dijkstra算法
/**
Dijkstra算法能够解决边权重非负的加权有向图的单起点最短路径问题。
Dijkstra算法和Prim算法比较:两种算法都会添加边的方式构造一棵树,Prim算法每次添加的都是离树最近的非树顶点,
Dijkstra算法每次添加的都是离起点最近的非树顶点。它们都不需要marked[]数组,因为条件!marked[i]等价于
条件distTo[i]无穷大
*/
class DijkstraSP
{
public:
	DijkstraSP(EdgeWeightDigraph &graph, size_t s) : edgeTo(graph.getArrSize()), distTo(graph.getArrSize())
	{
		for (size_t i = 0; i < graph.getArrSize(); i++)
			distTo[i] = DBL_MAX; // 默认无穷大
		distTo[s] = 0;

		que.push_back(pair<size_t, double>(s, 0.0));
		while (!que.empty())
		{
			size_t v = que[0].first;
			que.erase(que.begin());
			relax(graph, v);
		}
	}

	double getDistTo(size_t v) const { return (v < distTo.size()) ? distTo[v] : DBL_MAX; }
	bool hasPathTo(size_t v) const { return (v < distTo.size()) ? (distTo[v] != DBL_MAX) : false; }
	vector<DirectedEdge> getPathTo() const { return edgeTo; }

private:
	void relax(EdgeWeightDigraph &graph, size_t v)
	{
		vector<DirectedEdge> vec = graph.adj(v);

		for (size_t i = 0; i < vec.size(); i++)
		{
			size_t w = vec[i].to();

			// distTo[w]表示从s到w的最短路径的长度
			if (distTo[w] > distTo[v] + vec[i].weight())
			{
				distTo[w] = distTo[v] + vec[i].weight();
				edgeTo[w] = vec[i];

				size_t index = queHasVertax(w);
				if (index != que.size()) // 队列中包含节点w
					que[index].second = distTo[w];
				else
					que.push_back(pair<size_t, double>(w, distTo[w]));
			}
		}
	}

	size_t queHasVertax(size_t v)
	{
		for (size_t i = 0; i < que.size(); i++)
		{
			if (que[i].first == v)
				return i;
		}
		return que.size();
	}

	vector<DirectedEdge> edgeTo; // edgeTo[]中元素所对应的的可达顶点构成了一棵最短路径树
	vector<double> distTo; // distTo[]记录节点到起点的最短路径长度,初始化微无穷大
	vector<pair<size_t, double>> que; // 用vector来代替队列,队列pop相当于vec.erase(vec.begin())操作
};

int main(void)
{
	EdgeWeightDigraph graph(8);

	graph.addEdge(DirectedEdge(4, 5, 0.35));
	graph.addEdge(DirectedEdge(5, 4, 0.35));
	graph.addEdge(DirectedEdge(4, 7, 0.37));
	graph.addEdge(DirectedEdge(5, 7, 0.28));
	graph.addEdge(DirectedEdge(7, 5, 0.28));
	graph.addEdge(DirectedEdge(5, 1, 0.32));
	graph.addEdge(DirectedEdge(0, 4, 0.38));
	graph.addEdge(DirectedEdge(0, 2, 0.26));
	graph.addEdge(DirectedEdge(7, 3, 0.39));
	graph.addEdge(DirectedEdge(1, 3, 0.29));
	graph.addEdge(DirectedEdge(2, 7, 0.34));
	graph.addEdge(DirectedEdge(6, 2, 0.40));
	graph.addEdge(DirectedEdge(3, 6, 0.52));
	graph.addEdge(DirectedEdge(6, 0, 0.58));
	graph.addEdge(DirectedEdge(6, 4, 0.93));

	cout << graph.getVertax() << endl;
	cout << graph.getEdge() << endl;
	cout << "-------------------" << endl;
	graph.printGraph();
	cout << endl;

	// 输出起点0到图中所有点的最短路径的长度
	DijkstraSP dijk(graph, 0);
	for (size_t i = 0; i < graph.getArrSize(); i++)
	{
		cout << "0 -> " << i << ": " << dijk.getDistTo(i) << endl;
	}
	cout << endl;

	system("pause");
	return 0;
}

void EdgeWeightDigraph::addEdge(const DirectedEdge &e)
{
	if (e.from() >= getArrSize())
		return;

	arr[e.from()].push_back(e);
	this->edge++; // 边的个数加1
}

vector<DirectedEdge> EdgeWeightDigraph::adj(size_t v) const
{
	if (v < getArrSize())
		return arr[v];
	else
		return vector<DirectedEdge>(); // a blank vector
}

vector<DirectedEdge> EdgeWeightDigraph::edges() const
{
	vector<DirectedEdge> vec;

	for (size_t i = 0; i < getArrSize(); i++)
	{
		for (size_t j = 0; j < arr[i].size(); j++)
			vec.push_back(arr[i][j]);
	}
	return vec;
}

void EdgeWeightDigraph::printAdj(size_t v) const
{
	if (v >= getArrSize())
		return;
	for (size_t i = 0; i < arr[v].size(); i++)
		arr[v][i].print();
	cout << endl;
}

void EdgeWeightDigraph::printGraph() const
{
	for (size_t i = 0; i < getArrSize(); i++)
		printAdj(i);
}

参考资料

        1、https://github.com/luoxn28/algorithm_data_structure

        2、《算法 第4版》 图相关章节

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

加权无向图

用数学语言讲,设G为图,对图的每一条边e来说,都对应于一个实数W(e)(可以通俗的理解为边的“长度”,只是在数学定义中图的权可以为负数),我们把W(e)称为e的“权”。把这样的图G称为“加权图”。 ...

算法——图之加权图

加权图这里指无向加权图。 加权图是一种为每条边关联一个权值或成本的图模型。也就是在无向图的基础上,每条边加上权值。 加权图有很多应用,例如航空图中,边表示航线,权值表示距离或是费用。还能表示电路图...

算法——图之加权有向图

这篇讨论加权有向图。 加权有向图是在有向图的基础上,边的赋予权重信息的。 加权有向图有很多应用。最典型的就是最短路径问题。我们日常生活中也经常遇到这种问题,例如从一个点出发,到达另外一个点,怎么过去才...

java实现图的最短路径(SP)的迪杰斯特拉(Dijkstra)算法

/****************************************************************************** * Compilation: ja...

Dijkstra最短路径算法(针对加权有向图)

indexMinPQ.h #ifndef _INDEX_MIN_PQ_H_ #define _INDEX_MIN_PQ_H_ #define INDEX_MIN_PQ_TEST 0 typed...

dijkstra算法R语言

L2-001. 紧急救援-PAT团体程序设计天梯赛GPLT(Dijkstra算法)

L2-001. 紧急救援 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在...

Dijkstra算法

  • 2013-11-30 22:32
  • 1.84MB
  • 下载

Dijkstra算法求最短路

  • 2014-08-13 19:40
  • 27KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)