(1小时数据结构)数据结构c++描述(三十)--- 图(Dijkstra算法 与 Floyd算法 )

  • 单源最短路径问题是:给定带权的有向图,对于给定的源点v0,求从v0到其余所有顶点的最短路径。
  • 所有顶点之间的最短路径问题:给定带权的有向图,求出所有的定点的最短路径

如果解决的问题:

(1小时数据结构)数据结构c++描述(三十)--- 图(Dijkstra算法 与 Floyd算法 )_第1张图片

 

Dijkstra算法: 

 Dijkstra算法就是解决单源最短路径问题:

步骤:

产生从源点v0到它自身的路径,其长度为0,将源点v0加入最短路径S中。这些通过以下代码就可以实现:

    mark[v0] = true;
    path[v0] = -1;
    curShortLen[v0] = 0;

(2)更新和源点v0直接邻接的所有顶点i对应的curShortLen[i]。 
(3)然后找出第一条最短路径及其顶点k。更新path[k]=v0。 
(4)将顶点k加入S,并对与顶点k直接邻接的所有顶点i对应的curShortLen[i]进行更新,更新公式为curShortLen[i] = min{curShortLen [i],curShortLen[k]+w(k,i)},其中w(k,i)是边< k,i >上的权值。 
(5)求下一条最短路径的终点,也就是还没有加入最短路径的顶点中具有最短的curShortLen[k]值的顶点k。 
(6)重复(4)和(5),直到将所有从源点v0可达的顶点都加入最短路径中。 
其实,上面步骤中的(4)、(5)和(2)、(3)完全是一样的,我在用代码实现的时候也是将其视为统一情况处理。

 代码部分:

//Dijkstra算法的辅助函数,用于找出下一条最短路径的终点
template
int Graph::FinMinLen(T * curShortLen, bool * mark)
{
	int minIndex = -1;
	T minLen = INT_MAX;

	for (int i = 1; i < n; ++i) {
		if (!mark[i] && minLen > curShortLen[i]) {
			minIndex = i;
			minLen = curShortLen[i];
		}
	}
	return minIndex;
}


//迪杰斯特拉算法解决单源最短路径问题
template
void Graph::Dijkstra(int v0)
{
	if (v0 < 0 || v0 > n - 1) {
		cout << "input error!" << endl;
		return;
	}
	T *curShortLen = new T[n];          //curShortLen[i]存放从源点v0到i的当前最短路径的长度
	int *path = new int[n];             //path[i]给出从v0到顶点i的最短路径上,位于顶点i前面的那个顶点

	for (int i = 0; i < n; ++i) {
		curShortLen[i] = INT_MAX;
		path[i] = -1;
	}
	Dijkstra(v0, path, curShortLen);
}


//迪杰斯特拉算法解决单源最短路径问题,私有,内部调用
template
void Graph::Dijkstra(int v0, int * path, T * curShortLen)
{
	bool *mark = new bool[n];        //mark[i]表示顶点i是否已加入单源最短路径里
	for (int i = 0; i < n; ++i) {
		mark[i] = false;
	}


	mark[v0] = true;
	path[v0] = -1;
	curShortLen[v0] = 0;

	int k = v0;                     //最近加入单源最短路径中的顶点
	int nextK = -1;                 //即将加入单源最短路径中的顶点
	ENode *p;
	int count = 0;                  //用来计数单源最短路径上有多少条边

	for (int i = 1; i < n; ++i) {   //循环n-1次,将其他顶点都加入单源最短路径中
		for (p = enodes[k]; p; p = p->next) {
			int j = p->adjVex;
			if (!mark[j] && curShortLen[j] > curShortLen[k] + p->weight) {
				curShortLen[j] = curShortLen[k] + p->weight;    //保证curShortLen[j] = min{curShortLen[j],curShortLen[k]+p->weight}
			}
		}
		nextK = FinMinLen(curShortLen, mark);   //找到下一条最短路径的终点
		if (-1 == nextK) {                      //返回-1,说明从v0出发的单源最短路径已经都找到了
			break;
		}
		else {
			mark[nextK] = true;                     //加入最短路径中
			path[nextK] = k;                        //记录终点信息,方便回溯
			k = nextK;                              //k指向最近加入的顶点
			count++;                                //路径上的边数加1
		}
	}

	//输出最短路径结果
	cout << "shortest path:" << endl;
	int lastVer;    //最短路径中的上个顶点
	stack tmp; //用栈来逆序储存最短路径上的顶点
	for (int i = 1; i <= count; ++i) {
		cout << curShortLen[k] << " : ";

		tmp.push(k);
		lastVer = path[k];
		while (lastVer != v0) {
			tmp.push(lastVer);
			lastVer = path[lastVer];
		}
		tmp.push(v0);

		cout << tmp.top();
		tmp.pop();
		while (!tmp.empty()) {
			cout << "->" << tmp.top();
			tmp.pop();
		}
		cout << endl;

		k = path[k];    //将k置为最短路径上在该点之前的那个顶点
	}
}

 Floyd算法 

解决所有顶点之间的最短路径。

步骤:

      Floyd算法的思想是:设集合S的初始状态为空集合,然后依次向集合S中加入顶点0,1…,n-1,每次加入一个顶点,我们更新d[i][j]。d[i][j]被定义为从i到j中间只经过S中的顶点的、所有可能路径中的最短路径的长度。如果从i到j,中间只经过S中的顶点当前没有路径相通,那么d[i][j]为一个大值INT_MAX。随着S中的顶点不断增加,d[i][j]的值不断修正,当所有顶点都加入S中时,d[i][j]的值就是从i到j的最短路径。

代码:

//获得边u-v的权值
template
T Graph::GetWeight(int u, int v)
{
	if (u == v) {
		return 0;
	}
	ENode *p = enodes[u];
	while (p != NULL && p->adjVex != v) {
		p = p->next;

	}

	if (p) {
		return p->weight;
	}
	else {
		//        cout<<"edge "<
void Graph::Floyd()
{
	int path[n][n];    //n*n矩阵,path[i][j]表示从顶点i到j的最短路径上,顶点j的前一个顶点
	T d[n][n];         //d[i][j]存放从顶点i到顶点j的当前最短路径的长度
	int i, j, k;

	//初始化矩阵
	for (i = 0; i < n; i++) {
		for (j = 0; j < n; j++) {
			d[i][j] = GetWeight(i, j);
			if (i != j && d[i][j] < INT_MAX) {
				path[i][j] = i;
			}
			else {
				path[i][j] = -1;
			}
		}
	}

	for (k = 0; k < n; k++) {       //n次更新矩阵
		for (i = 0; i < n; i++) {
			for (j = 0; j < n; j++) {
				if (d[i][k] + d[k][j] < d[i][j])
				{  //加入顶点k之后更新矩阵
					d[i][j] = d[i][k] + d[k][j];
					path[i][j] = path[k][j];
				}
			}
		}
	}

	//输出所有顶点之间的最短路径结果
	cout << "shortest path between two vertex:" << endl;
	stack tmp; //用栈来逆序储存最短路径上的顶点
	int m;
	for (i = 0; i < n; i++) {
		for (j = 0; j < n; j++) {
			if (i == j) {
				continue;
			}
			cout << "from " << i << " to " << j << " : ";

			if (path[i][j] == -1) {     //表示不可达
				cout << "not connected" << endl;
			}
			else {
				tmp.push(j);
				m = path[i][j];
				while (m != -1) {    //在最短路径上进行反向回溯
					tmp.push(m);
					m = path[i][m];
				}

				cout << tmp.top();
				tmp.pop();
				while (!tmp.empty()) {
					cout << "->" << tmp.top();
					tmp.pop();
				}
				cout << endl;
			}

		}
	}
}

       有关基础的定义在我博客图的章有全部源码,可以关注我的博客,在数据结构与算法的章节,有相关的源码,与对应的博客,小伙伴们,一起加油吧。

你可能感兴趣的:(数据结构与算法,数据结构,c++,算法,Dijkstra算法,Floyd算法)