您的位置:首页 > 理论基础 > 数据结构算法

数据结构——最短路径Floyd算法

2018-02-03 15:31 399 查看

                     最短路径Floyd算法

       上一篇博客讲到了Dijkstra算法的原理和用C++的代码实现。Dijkstra算法可以解决任意点到其他点的最短路径问题。在Dijkstra算法中,最后一个循环是个双层循环,在最坏情况下,每个节点都可以指向其他所有节点,那么Dijkstra算法的时间复杂度就是O(n^2)了。如果想让图中每个点到其他所有点的最短路径,就需要把Dijkstra算法执行n次,那么整个算法的时间复杂度就是O(n^3)了。弗洛伊德(Floyd)算法的时间复杂度也是O(n^3),但Floyd算法更加简单。
       Floyd算法把dist的最终结果存在一个二维数组dist[i][j]中,dist[i][j]表示从i到j的最短路径长度
bf3b
,而路径存放在path中,path[i][j]=k表示路径为(i,...,k,j),也就是j的前一个节点是k,如果想要k的前一个节点,则是path[i][k],这样一直找下支,就可以得到i到j的完整路径。
      Floyd算法是分步进行的,把dist扩展一维,形成dist[k][i][j],表示i到j的最短路径中i和j之间的节点的序号最大为k,那么最后要求的最短路径的矩阵就是dist[n-1]了。当k最小为-1时,表示i和j之间的最短路径不能有节点,而k=0时表示之间的节点序号最大不能为0。这种策略的好处就是逐渐向最短路径中添加新的节点,如果添加后路径变短了,就添加,如果没有变短就不添加。并且由于所有的最短路径在形式上都是等价的,因此可以选择拼接最短路径,这样效率更高。因为如果a->b->d比a->c->d更短,并且有e->f,那么从a->f的最短路径中,绝对不可能是a->c->d->e->f,而仅可能是a->b->d->e->f。这种思路更加清晰。
下面是用C++实现的Floyd算法
#include "stdafx.h"
#include <iostream>
using namespace std;

const int MAX = 1e5;

/**
* 求当前节点的第一个邻接节点
*/
int FirstAdjVex(int **weights,int size,int cv)
{
if(cv < 0 || cv >= size)
{
return -1;
}
for (int i = 0;i < size;i++)
{
if (weights[cv][i])
{
return i;
}
}
return -1;
}

/**
* 计算当前节点cv基于av的下一个邻接节点
*/
int NextAdjVex(int **weights,int size,int cv,int av)
{
if (cv < 0 || cv >= size || av < 0 || av >= size - 1)
{
return -1;
}

for (int i = av + 1;i < size;i++)
{
if (weights[cv][i])
{
return i;
}
}
return -1;
}

void Floyd(int **weights,int size,int **dist,int **paths)
{
//初始化dist
for (int i = 0;i < size;i++)
{
for (int j = 0;j < size;j++)
{
if(i==j)
{
dist[i][j] = 0;
}else if(weights[i][j] == 0)//i和j不相等且j不是i的邻接节点
{
dist[i][j] = MAX;
}
else
{
dist[i][j] = weights[i][j];
}
if(i!=j&&dist[i][j]<MAX)//如果i和j不相等并且j是i的邻接节点
{
paths[i][j] = i;
}
else
{
paths[i][j] = -1;
}
}
}
for (int k = 0;k < size;k++)//k的0到n-1
{
for (int i = 0;i < size;i++)
{
for (int j = 0;j < size;j++)
{
if(dist[i][k]+dist[k][j]<dist[i][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
paths[i][j] = paths[k][j];
}
}
}
}
}

int main()
{
//构造有向图
int size = 3;
int **weights = new int*[size];
for (int i = 0;i < size;i++)
{
weights[i] = new int[size];
for (int j = 0;j < size;j++)
{
weights[i][j] = 0;
}
}
weights[0][1] = 4;
weights[0][2] = 11;
weights[1][0] = 6;
weights[1][2] = 2;
weights[2][0] = 1;
int **paths = new int*[size];//存放路径
int **dist = new int*[size];//存入v0到每个节点的最短路径的长度
for (int i = 0;i < size;i++)
{
paths[i] = new int[size];
dist[i] = new int[size];
}
Floyd(weights, size, dist, paths);

for (int i = 0;i < size;i++)
{
for (int j = 0;j < size;j++)
{
cout << dist[i][j] << "  ";
}
cout << "         ";
for (int j = 0;j < size;j++)
{
cout << paths[i][j] << "  ";
}
cout << endl;
}

cout << "--------------------------------" << endl;
int index;
for (int i = 0;i < size;i++)
{
for (int j = 0;j < size;j++)
{
if (i != j)
{
cout << i << " ---> " << j << " dist: " << dist[i][j] << endl;
for (index = j;;)
{
if(index == i)
{
cout << i;
break;
}
if (paths[i][index] < 0)
{
cout << "no way!";
break;
}
cout << index << " <- ";
index = paths[i][index];
}
cout << endl;
}
}
}

system("pause");
return 0;
}


下面是执行结果
横线上面是打印的dist矩阵和path矩阵,下面的是每个节点到其他所有节点的最短路径的长度以及路径

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: