Dijkstra算法学习

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;
}
发布了47 篇原创文章 · 获赞 32 · 访问量 7万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章