c++实现Dijkstra算法寻找有向无权图的最短路径

Dijkstra算法常用来求图中单个源点到其他各点的最短路径,该算法采用贪心策略,每次都挑选最短路径的顶点。对每个结点使用时可求图中任意两点间的最短路径,不过求图中任意两点间的路径时常使用Floyd算法实现。

本次使用的图为有向带权图,存储结构为邻接矩阵,该存储结构更适合稠密图。

一、求解过程

1.将网(带权的图)中的顶点分为两组,一组为已知最短路径的顶点,一组为未知的。后面将通过此算法不断将未知集中的顶点加入已知集。

2.此算法依赖三个容器,在此使用的是数组。分别为dist[i](存储顶点Vi到起始点的距离),path[i](存储顶点Vi的前驱顶点)和s[i](用来标记是否已经访问过顶点Vi

3.算法将依次将路径最短的顶点加入已知集,每加入一个新顶点时,就要进行一次遍历,将最新找到顶点的邻接点的dist[]更新(松弛),这是由于每当一个顶点进入时,总是这个顶点的邻接点的dist[]会更新。

 for (int i = 1; i < n; i++)//n个顶点的图,需要找n-1个顶点的最小路径
    {

        min = MaxInt;//最开始赋予不与V0相邻的顶点的dist[]
        for (int w = 1; w <= n; w++)
            if (!S[w] && dist[w] < min) { v = w; min = dist[w]; }//循环,找一条路径最小的边,并将这条边的终点记为v
        S[v] = true; //表示v已被收入已知集
    
        for (int w = 1; w <= n; w++) //收入v后开始更新v的其余顶点的dist[]
            if (!S[w] && (dist[v] + G.arcs[v][w] < dist[w]))
            {
                dist[w] = dist[v] + G.arcs[v][w];
                Path[w] = v;
            }
    }

4.最终所有顶点的最小路径都已找到后,path[]其实是倒叙存放路径经过的顶点,使用一个栈结构可将其正序输出。

for (int i = 1; i <= n; i++)
    {
        cout << G.vexs[v0]<<"到" << G.vexs[i] <<"的最短路径长度为"<< dist[i];
        int j = i;
        int t = i;
        if (Path[j] == -1) cout << endl; //处理v0和与v0不通的顶点,该类顶点和v0之间不存在最短路径,所以path为初始化时的值,此处为-1
        if (Path[j] != -1)
        {
            cout << " " << "路径为";

            while (Path[j] != -1)//循环,将一个顶点的前面的所有顶点全部压入栈
            {
                Push(s, Path[j]); 
                j = Path[j]; 
            }
            while (s.top != s.base)//输出
            {
                int pathname = -1;
                Pop(s, pathname);
                cout << G.vexs[pathname] << " ";
            }
            cout << G.vexs[t];
            cout << endl;
        }

    }

二、全部代码

#include <iostream>
using namespace std;
int const MaxInt = 10000;
#define MVNum 100//最大顶点个数


typedef string VerTexType; //假设顶点的数据类型为字符型
typedef int ArcType;//假设边的权值为整型

typedef struct
{
    VerTexType vexs[MVNum + 1];//顶点表
    ArcType arcs[MVNum + 1][MVNum + 1]; //邻接矩阵,也即二维数组
    int vexnum, arcnum;//图当前的点数和边数
}AMGraph;

typedef struct
{
    int stacksize;
    int* base;
    int *top;
}SqStack;
//图的邻接矩阵表示法
void CreateUDN(AMGraph* G)//创建无向图,采用邻接矩阵表示法
{
    cout << "请输入图的顶点数和边数" << endl;
    cin >> G->vexnum >> G->arcnum;//输入总顶点数和总边数

    for (int i = 1; i <= G->vexnum; i++)
    {
        cout << "请输入第" << i << "个顶点的信息" << endl;
        cin >> G->vexs[i];
    }//依次输入点的信息



    for (int i = 1; i <= G->vexnum; i++)   //初始化邻接矩阵,边的权值均设置为最大值
    {
        for (int j = 1; j <= G->vexnum; j++)
            G->arcs[i][j] = MaxInt;
    }
    cout << "请输入依次输入各边的两个顶点和权值" << endl;
    for (int k = 1; k <= G->arcnum; k++)
    {
        int  v1, v2;//v1和v2为两个点的位置 
        ArcType w;//w为边的权值
        cout << "第" << k << "条边:";
        cin >> v1 >> v2 >> w;//输入一条边的依附顶点及权值
        G->arcs[v1][v2] = w;
    }

}

void DijkstraPath(AMGraph G, int v0)
{
    int n = G.vexnum;
    bool* S = new bool[n + 1];//判断是否走过
    int* dist = new int[n + 1];
    int* Path = new int[n + 1];
    for (int v = 1; v <= n; v++)//对各个顶点进行初始化
    {
        S[v] = false;
        dist[v] = G.arcs[v0][v];
        if (dist[v] < MaxInt) Path[v] = v0;
        else Path[v] = -1;
    }
    S[v0] = true;
    dist[v0] = 0; //至此已经完成对S[v],dist[v],path[v]的初始化。

    int w = 0;
    int v = 0;
    int min = MaxInt;

    for (int i = 1; i < n; i++)
    {

        min = MaxInt;
        for (w = 1; w <= n; w++)
            if (!S[w] && dist[w] < min) { v = w; min = dist[w]; }//循环,找一条路径最小的边
        S[v] = true;
    
        for (w = 1; w <= n; w++)
            if (!S[w] && (dist[v] + G.arcs[v][w] < dist[w]))
            {
                dist[w] = dist[v] + G.arcs[v][w];
                Path[w] = v;
            }
    }
    void Push(SqStack & s, int e);
    void Pop(SqStack & s, int& e);
    void InitStack(SqStack & s);
    SqStack s;
    InitStack(s);




    for (int i = 1; i <= n; i++)
    {
        cout << G.vexs[v0]<<"到" << G.vexs[i] <<"的最短路径长度为"<< dist[i];
        int j = i;
        int t = i;
        if (Path[j] == -1) cout << endl;
        if (Path[j] != -1)
        {
            cout << " " << "路径为";

            while (Path[j] != -1)
            {
                Push(s, Path[j]);
                j = Path[j];
            }
            while (s.top != s.base)
            {
                int pathname = -1;
                Pop(s, pathname);
                cout << G.vexs[pathname] << " ";
            }
            cout << G.vexs[t];
            cout << endl;
        }

    }

    

}


int main()
{
    void CreateUDN(AMGraph * G);
    void DijkstraPath(AMGraph G, int v0);
    AMGraph G;
    CreateUDN(&G);
    int v0 = 1;
    DijkstraPath(G, v0);
    return 0;
}


void InitStack(SqStack& s)
{
    s.base = new int[101];
    s.top = s.base;
    s.stacksize = 101;

}

void Push(SqStack& s, int e)
{
    *s.top++ = e;
}
void Pop(SqStack& s, int& e)
{
    e = *--s.top;
}

三、时间复杂度

扫描所有未收录顶点-O(|V|)
对每个顶点需要扫描其余顶点更新dist[]-O(|V|²)

参考数据结构第二版-严蔚敏及浙大慕课数据结构-陈越姥姥

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值