Dijkstra算法学习

来源:互联网 发布:巨型海报打印软件 编辑:程序博客网 时间:2024/06/06 04:44

Dijkstra算法

Dijkstra算法是求解有向图最短路径的经典算法,计算从一个指定的初始结点到其他各个结点最短路径。它的理论基础就是一条最短路径的子路径也一定是最短的。

实现如下:

  1. 将所有结点分为两个集合,一个命名为S集,一个命名为U集。S集中的点是我们已知其最短路径的点,U集中的点是我们还未知其最短路径的点。因此初始时刻,S集中只有一个我们选定的起始点,U集中是除了起始点意外的所有点;而最终时刻,S集中应该包含所有的点,U集为空集。
  2. 从最后加入S集的u点出发,选出到U集中最短的那个点nextVertex,将nextVertex点加入S集,并从U集中移除nextVertex点。
  3. 更新U集各点到起点的距离。如果从起点到u点再到U集中某点的距离比之前保存的距离小,就更新,否则不更新。

图例:用Dijkstra算法求解如下图的最短路径
这里写图片描述
这里写图片描述
感觉这是我看到的一个最好理解图。

附上实现代码:

#include<iostream>#include<vector>#include<stack>using namespace std;int map[][5] = {     //邻接矩阵        {0,10,INT_MAX,INT_MAX,5},        {INT_MAX,0,1,INT_MAX,2},        {INT_MAX,INT_MAX,0,4,INT_MAX},        {7,INT_MAX,6,0,INT_MAX},        {INT_MAX,3,9,2,0}};void Dijkstra(        const int numOfVertex,   //图中结点个数        const int startVertex,   //起始结点编号        int map[][5],            //距离邻接矩阵        int* distance,           //起始结点到当前结点最短路径的距离        int* prevVertex          //路径中,当前点的上一个结点编号){    vector<bool> isIns;               //当前点所属集合,true表示在S中,false表示在U中    isIns.reserve(0);                 //预分配空间    isIns.assign(numOfVertex, false); //赋false初值    for(int i=0;i<numOfVertex;++i)        //初始化distance以及prevVertex    {        distance[i] = map[startVertex][i];//初始化distance        if(map[startVertex][i] < INT_MAX) //如果起点到当前点存在路径,则将当前点的上一点初始化为起始点            prevVertex[i] = startVertex;        else            prevVertex[i] = -1;           //不存在时设置为-1    }    prevVertex[startVertex] = -1;         //起始点的上一点为-1    int u = startVertex;                  //u为S集中最后加入的点,即从该点开始搜索    for(int i=1;i<numOfVertex;++i) {      //从U集中搜索当前distance最小点        int nextVertex = u;               //nextVertex为即将加入S集的点        int tempDistance = INT_MAX;        for (int j = 0; j < numOfVertex; ++j) {            if ((isIns[j] == false) && (distance[j] < tempDistance)) { //j不在S集且到j的距离比上一个点小                nextVertex = j;             //设置j为即将加入S集的点                tempDistance = distance[j]; //这不用解释了,太明显了不知道说些什么了            }        }        isIns[nextVertex] = true;           //U集中distance最小的点,加入S集        u = nextVertex;                     //u设置为S集中最后加入的点,接下来从这里开始继续找        for (int j = 0; j < numOfVertex; ++j) {     //更新U集中的distance            if ((isIns[j] == false) && (map[u][j] < INT_MAX)) {//如果U集,且有路径到达                int temp = distance[u] + map[u][j]; //比较从起始点到u再到j距离与之前j的distance                if (temp < distance[j]) {           //更小的时候就更新distance                    distance[j] = temp;                    prevVertex[j] = u;                }            }        }    }}int main(int argc,const char* argv[]){    int distance[5];    int preVertex[5];    for(int i=0;i<5;++i)    {        Dijkstra(5,i,map,distance,preVertex);        for(int j=0;j<5;j++)        {            int index = j;            stack<int> trace;            while(preVertex[index]!=-1)            {                trace.push(preVertex[index]);                index = preVertex[index];            }            cout<<"路径:";            while(!trace.empty())            {                cout << trace.top() << "--";                trace.pop();            }            cout<<j;            cout<<" 距离是 "<<distance[j]<<endl;        }    }    return 0;}
0 0