【算法】动画图解Dijkstra算法及其实现代码

本文介绍了Dijkstra算法,一种基于贪心思想的最短路径算法。内容包括算法的优先队列实现,动画演示,详细讲解,手动模拟过程以及代码实现。此外,还讨论了在处理无向边时的调整方法,对于邻接矩阵和邻接表的处理方式。
部署运行你感兴趣的模型镜像

Dijkstra算法是基于贪心思想的一种求最短路径的算法。
他的实现基于优先队列这种数据结构

该算法的动画演示
该算法的详细讲解
在这里插入图片描述

手动模拟示意图的结果
在这里插入图片描述
实现代码:

#include <iostream>
#include <vector>
using namespace std;
#include<stack>
const int INF = 1000000000;
 
/*Dijkstra算法解决的是单源最短路径问题,即给定图MGrap(V,E)和起点s(起点又称为源点),
求从起点s到达其它顶点的最短距离,并将最短距离存储在矩阵d中*/
void Dijkstra(int n, int s, vector<vector<int>> MGrap, vector<bool>& vis, vector<int>& d, vector<int>& pre)
{
       /*
       param
       n:           顶点个数
       s:           源点
       MGrap:           图的邻接矩阵
       vis:         标记顶点是否已被访问
       d:           存储源点s到达其它顶点的最短距离
       pre:         存储从起点s到达顶点v的最短路径上v的前一个顶点 (新添加)
       */
       fill(d.begin(), d.end(), INF);                         //初始化最短距离矩阵,全部为INF
 
       for (int i = 0; i < n; ++i)                            //新添加
              pre[i] = i;
 
       d[s] = 0;                                              //起点s到达自身的距离为0
       for (int i = 0; i < n; ++i)
       {
              int u = -1;                                     //找到d[u]最小的u
              int MIN = INF;                                  //记录最小的d[u]
              for (int j = 0; j < n; ++j)                     //开始寻找最小的d[u]
              {
                     if (vis[j] == false && d[j] < MIN)
                     {
                           u = j;
                           MIN = d[j];
                     }
              }
              //找不到小于INF的d[u],说明剩下的顶点和起点s不连通
              if (u == -1)
                     return;
              vis[u] = true;                                  //标记u已被访问
              for (int v = 0; v < n; ++v)
              {
                     //遍历所有顶点,如果v未被访问&&u能够到达v&&以u为中介点可以使d[v]更优
                     if (vis[v] == false && d[u] + MGrap[u][v] < d[v]) {
                           d[v] = d[u] + MGrap[u][v];             //更新d[v]
                           pre[v] = u;                        //记录v的前驱顶点为u(新添加)
                     }
              }
       }
}
 
//输出从起点s到顶点v的最短路径
void DFSPrint(int s, int v, vector<int> pre)
{
       if (v == s) {
              cout << s << " ";
              return;
       }
       DFSPrint(s, pre[v], pre);
       cout << v << " ";
}
 // 打印最短路径
void PrintShortPath(vector<vector<int>> G, int v0, vector<int> P, vector<int> D){
    int i, k;
    stack<int> path;
    cout<<"顶点v"<<v0<<"到其他顶点之间的最短路径如下: "<<endl;
    for(i = 0; i < G.size(); ++i){
        if(i == v0) continue;
        cout<<"v"<<v0<<"--"<<"v"<<i<<" weight: "<<D[i]<<"  Shortest path: ";
        path.push(i);
        int k = P[i];
        while(k != 0){
            path.push(k);
            k = P[k];
        }
        path.push(v0);
        while(!path.empty()){
            if(path.size() != 1)
                cout<<path.top()<<"->";
            else
                cout<<path.top()<<endl;
            path.pop();
        }
    }
}

int main()
{
       int n = 6;
       vector<vector<int>> MGrap = { {0,1,INF,4,4,INF},
                                 {INF,0,INF,2,INF,INF},
                                 {INF,INF,0,INF,INF,1},
                                 {INF,INF,2,0,3,INF},
                                 {INF,INF,INF,INF,0,3},
                                 {INF,INF,INF,INF,INF,0} };
       vector<bool> vis(n);
       vector<int> d(n);
       vector<int> pre(n);
 
       Dijkstra(n,0,MGrap,vis,d,pre);
       for (auto x : d)
              cout << x << " ";
       cout << endl;
       //输出从起点s到顶点v的最短路径
       DFSPrint(0, 5, pre);
       cout<<endl;
       PrintShortPath(MGrap,0,pre,d);
       return 0;
}

运行结果:
在这里插入图片描述
另外一种实现的方法

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

#define MAXVEX 9
#define INFINITY 65535

typedef int Patharc[MAXVEX];
typedef int ShortPathTable[MAXVEX];

typedef struct {
    int vex[MAXVEX];
    int arc[MAXVEX][MAXVEX];
    int numVertexes;
} MGraph;

// 构建图
void CreateMGraph(MGraph *G){
    int i, j, k;
    // 初始化图
    G->numVertexes = 9;
    for(i = 0; i < G->numVertexes; ++i){
        G->vex[i] = i;
    }
    for(i = 0; i < G->numVertexes; ++i){
        for(j = 0; j < G->numVertexes; ++j){
            if(i == j)
                G->arc[i][j] = 0;
            else
                G->arc[i][j] = G->arc[j][i] = INFINITY;
        }
    }

    G->arc[0][1] = 1;
    G->arc[0][2] = 5;

    G->arc[1][2] = 3;
    G->arc[1][3] = 7;
    G->arc[1][4] = 5;

    G->arc[2][4] = 1;
    G->arc[2][5] = 7;

    G->arc[3][4] = 2;
    G->arc[3][6] = 3;

    G->arc[4][5] = 3;
    G->arc[4][6] = 6;
    G->arc[4][7] = 9;

    G->arc[5][7] = 5;

    G->arc[6][7] = 2;
    G->arc[6][8] = 7;

    G->arc[7][8] = 4;

    // 设置对称位置元素值
    for(i = 0; i < G->numVertexes; ++i){
        for(j = i; j < G->numVertexes; ++j){
            G->arc[j][i] = G->arc[i][j];
        }
    }
}

void ShortPath_Dijkstra(MGraph G, int v0, Patharc P, ShortPathTable D){
    int final[MAXVEX];
    int i;
    for(i = 0; i < G.numVertexes; ++i){
        final[i] = 0;
        D[i] = G.arc[v0][i];
        P[i] = 0;
    }
    D[v0] = 0;
    final[v0] = 1;
    for(i = 0; i < G.numVertexes; ++i){
        int min = INFINITY;
        int j, k, w;

        for(j = 0; j < G.numVertexes; ++j){// 查找距离V0最近的顶点
            if(!final[j] && D[j] < min){
                k = j;
                min = D[j];
            }
        }
        final[k] = 1;
        for(w = 0; w < G.numVertexes; ++w){// 更新各个顶点的距离
            if(!final[w] && (min + G.arc[k][w]) < D[w]){
                D[w] = min + G.arc[k][w];
                P[w] = k;
            }
        }
    }
}

// 打印最短路径
void PrintShortPath(MGraph G, int v0, Patharc P, ShortPathTable D){
    int i, k;
    stack<int> path;
    cout<<"顶点v"<<v0<<"到其他顶点之间的最短路径如下: "<<endl;
    for(i = 0; i < G.numVertexes; ++i){
        if(i == v0) continue;
        cout<<"v"<<v0<<"--"<<"v"<<i<<" weight: "<<D[i]<<"  Shortest path: ";
        path.push(i);
        int k = P[i];
        while(k != 0){
            path.push(k);
            k = P[k];
        }
        path.push(v0);
        while(!path.empty()){
            if(path.size() != 1)
                cout<<path.top()<<"->";
            else
                cout<<path.top()<<endl;
            path.pop();
        }
    }
}

int main(int argc, char const *argv[]) {
    int v0 = 0; // 源点
    MGraph G;
    Patharc P;
    ShortPathTable D;
    CreateMGraph(&G);
    ShortPath_Dijkstra(G, v0, P, D);
    PrintShortPath(G, v0, P, D);
    return 0;
}

如果题目给出的是无向边(即双向边)而不是有向边,又该如何解决呢?其实很简单,只需要把无向边当成两条指向相反的有向边即可。对邻接矩阵来说,一条u与v之间的无向边在输入时可以分别对G[u][v]和G[v][u]赋以相同的边权;而对于邻接表来说,只需要在u的邻接表Adj[u]末尾添加上v,并在v的邻接表Adj[v]末尾添加上u即可。

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值