C++数据结构-图的单源最短路径迪杰斯特拉算法

#include <iostream>
#define MAXVEX 5     //结点数(初始默认6顶点,更改的话直接在这里修改即可)
#define MAXEDGE 8     //边数(初始默认10条边,更改的话直接在这里修改即可)
#define INFINITY 65535 //表示无穷大
using namespace std;

//下面代码是有向图的邻接矩阵(某顶点到其他顶点的最短距离)单源最短路径的迪杰斯特拉算法
//注意点: 下标0的位置都不用,所以要多开辟一个空间
//注意点:此程序主要通过迪杰特斯拉得到dist数组的值和pre数组
//注意点:最后的输出结是通过这两个数组来的(借助栈)

//若改为无向图的邻接矩阵迪杰斯特拉算法,则:
//增加下面的一句代码g.matrix[n][m]=1;

typedef struct
{
    int  vexNum;                     //顶点数
    int  edgeNum;                    //边数
    int  matrix[MAXVEX+1][MAXVEX+1]; //二维数组表示矩阵
    char vexinfo[MAXVEX+1];          //存放结点数组的值(如A,B,C,D)
}AdjMatr;                            //邻接矩阵

typedef struct sqstack
{
    int *elem;
    int top;
}SqStack;                 //栈

/*****************初始化静态栈******************/
void InitStack(SqStack & s)
{
    s.elem =new int[MAXVEX+1];
    s.top=0;
}
/******************压栈*************************/
//进栈是从下标1开始存放,0位置不存放数据
void Push(SqStack &s , int e)
{
    s.top++;
    s.elem[s.top]=e;
}
/******************出栈*************************/
void Pop(SqStack &s , int &e)
{
    e=s.elem[s.top];
    s.top--;
}
/******************判断是否空栈*****************/
int Emptystack(SqStack &s)
{
    if(s.top<1)
        return 0;
    else
        return 1;
}
/*********************初始化邻接矩阵************************/
void initAdjMatr(AdjMatr &g )
{
    g.vexNum = MAXVEX;   //顶点数
    g.edgeNum = MAXEDGE; //边数
    //初始化矩阵信息,初始为,一个不可能的数字表示这两个顶点之间不存在边
    for(int i=1;i<=MAXVEX;i++)
    {
        for(int j=1;j<=MAXVEX;j++)
            g.matrix[i][j]=INFINITY;
    }
    //初始化结点信息,(如A,B,C,D)
    for(int i=1;i<=MAXVEX;i++)
    {
        cout<<"请输入第"<<i<<"个结点的信息:";
        cin>>g.vexinfo[i];
    }
}
//通过结点信息(A,B,C,D之类)来查找对应矩阵下标
/*********************确定边在矩阵的位置*********************/
void locata(AdjMatr &g,char &vex1,char &vex2, int &m, int &n)
{
    for(int i =1;i<=MAXVEX;i++)
    {
        if(vex1 == g.vexinfo[i])
            m=i;
        if(vex2 == g.vexinfo[i])
            n=i;
    }
}
/*********************创建图对应的邻接矩阵************************/
void setAdjMatr(AdjMatr &g)
{
     //根据输入的两个顶点,来更新矩阵的值
     for(int i=1;i<=g.edgeNum;i++)
    {
        int weight;//两边之间的权值
        char vex1,vex2; //接受输入的两个顶点,来表示从vex1到vex2这条边
        cout<<"请输入第"<<i<<"条边的信息(形如A B 7,表示从A到B的一条边权值7):";
        cin>>vex1>>vex2>>weight;
        int m,n;        //m和n是用来接受vex1和vex2所在的下标值,好据此更新矩阵相应位置的值
        locata(g,vex1,vex2,m,n);
        g.matrix[m][n]=weight;
        //g.matrix[n][m]=weight;//无向图邻接矩阵对称,加上这句代码就是无向图的邻接矩阵了
    }
}
/**********************单源最短路径之迪杰斯特拉算法************************/
void Dijkstra(AdjMatr &g,int *dist,int *pre,int *visited,int first)
{
    int k;
    int v=first;  //表示要求的是从顶点v到其他顶点的最短路径,如果要求别的顶点到其他顶点的最短路径直接在这里修改即可
    for(int i=1;i<=MAXVEX;i++) //初始化数据
    {
        visited[i]=0;   //表示初始时,全为未知最短路径的状态
        dist[i]=g.matrix[v][i];//将与源点v有连线的顶点加上权值
        pre[i]=0;
    }
    for(int i=1;i<=MAXVEX;i++)
    {   //初始化全部顶点的直接前驱为
        if(dist[i]==INFINITY) //说明v和i不是邻接点,此时设置i的直接前驱为-1,表示无直接前驱
            pre[i]=-1;
        else                  //说明v和i是邻接点,此时设置i的直接前驱为1
            pre[i]=v;
    }
    dist[v]=0;    //源点v到v的路径为0
    visited[v]=1; //表示源点到源点的最短路径已经找到
    //开始进行循环,每次循环会找到一条源点到某个顶点的最短路径,n个结点则一共要找n-1条最短路径,所以循环n-1次
    for(int i=2;i<=MAXVEX;i++)
    {
        int Min = INFINITY;
        //此循环是要找出离源点v最近的顶点和距离
        for(int j=1;j<=MAXVEX;j++)
        {
            if(visited[j]==0 && dist[j] < Min)
            {
                k=j;//离源点v最近的顶点k下标
                Min=dist[j]; //离源点v最近的顶点k的距离
            }
        }
        visited[k]= 1;//表示已经找到离源点最近的顶点k
        //现在就是借助已找到的最短距离(即visited[k]=0)的顶点,看看源点到其他顶点的路径会不会更短
        for(int j=1;j<=MAXVEX;j++)
        {   //如果源点借助k顶点到j的路径,比源点直接到j的路径短的话
            //其实这里主要是看看跟k相邻的顶点的dist值需不需要更改而已
            if(visited[j] ==0 && (Min + g.matrix[k][j] < dist[j]))
            {   //说明借助k找到了源点到顶点j的更短路径,此时修改dist[j]和pre[j]的值
                dist[j]=Min + g.matrix[k][j];
                pre[j]=k;
            }
        }
    }
}
/*******************查看dist、pre及visited数组********************/
//这个函数主要是方便理解这三个数组值的变化
void showArray(int *dist, int*pre, int *visited)
{
    cout<<"dist数组情况:"<<endl;
    for(int i=1;i<=MAXVEX;i++)
        cout<<dist[i]<<"  ";
    cout<<endl;
    cout<<"pre数组情况:"<<endl;
    for(int i=1;i<=MAXVEX;i++)
        cout<<pre[i]<<"  ";
    cout<<endl;
    cout<<"visited数组情况:"<<endl;
    for(int i=1;i<=MAXVEX;i++)
        cout<<visited[i]<<"  ";
    cout<<endl;
}
/********************利用栈输出单源最短路径***********************/
void ShowDijkstra(AdjMatr &g,int *dist, int*pre, int v) //v是源点
{
    int temp;
    cout<<"迪杰特斯拉算法,单源"<<v<<"到其他顶点的最短路径如下:"<<endl;
    for(int i=1;i<=MAXVEX;i++)
    {
        temp=i;
        SqStack s;           //创建一个栈
        InitStack(s);        //初始化栈
        if(pre[temp] != -1)  //表示无直接前驱,即源点v到该点无路径
        {
             while(temp!=-1) //把顶点压栈,这里利用的是pre数组的直接前驱作用
             {
                Push(s,temp);
                temp=pre[temp];
             }
        }
        if(Emptystack(s) != 0 ) //栈非空
        {
            cout<<g.vexinfo[v]<<"->"<<g.vexinfo[i]<<"的最短路径是: "<<dist[i]<<"  ";
            while(s.top >=1)
            {   //这里的if-else是用来控制"->"
                if(s.top>1)
                {
                    Pop(s,temp);
                    cout<<g.vexinfo[temp]<<"->";
                }else//表示是最后一个元素了
                {
                    Pop(s,temp);
                    cout<<g.vexinfo[temp]<<endl;
                }
            }
        }else //栈为空,表明从源点v到该点无路径
             cout<<g.vexinfo[v]<<"->"<<g.vexinfo[i]<<"的最短路径是: "<<dist[i]<<endl;
    }
}
int main()
{
    int dist[MAXVEX+1];     //表示顶点v到顶点i的最短路径
    int pre[MAXVEX+1];      //表示从源点到顶点i的最短路径上i的直接前驱结点,无直接前驱则该值为-1
    int visited[MAXVEX+1] ; //表示是否求得顶点v到i的最短路径,求得则为1,没求得就为0
    AdjMatr g;
    initAdjMatr(g);
    setAdjMatr(g);
    int v = 1;    //表示要求的是从顶点1到其他顶点的最短路径,如果要求别的顶点到其他顶点的最短路径直接在这里修改即可
    Dijkstra(g,dist,pre,visited,v);
    showArray(dist,pre,visited); //显示这三个数组的情况
    ShowDijkstra(g,dist,pre,v);  //利用这三个数组输出单源最短路径的具体情况
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43323201/article/details/84792404