数据结构实验-图的最短路径算法实现

数据结构-图的最短路径算法实现

十四、图的最短路径算法实现

1、采用书上第 161 页定义的图的邻接矩阵存储表示,编程实现产生最短路径的 Dijkstra 算法。

/*采用书上第 161 页定义的图的邻接矩阵存储表示,编程实现产生最短路径的 Dijkstra 算法。*/
#include<stdio.h>
#include<stdlib.h>
//#include<limits.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define INFINITY 32767//最大值
#define MAX_VERTEX_NUM 20//最大顶点个数
typedef int Status;
typedef int VRType;
typedef int InfoType;
typedef enum {DG,DN,UDG,UDN}GraphKind;//{有向图,有向网,无向图,无向网}
typedef struct ArcCell{
    VRType adj;//VRType是顶点关系类型。对无权图,用0或1
                //表示相邻否;对带权图,则为权值类型
    InfoType *info;//该弧相关信息的指针
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef char VertexType;
typedef struct{
    VertexType vexs[MAX_VERTEX_NUM];//顶点向量
    AdjMatrix arcs;//邻接矩阵
    int vexnum,arcnum;//图的当前顶点数和弧数
    GraphKind kind;//图的种类标志
}MGraph;

typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];

int LocateVex(MGraph G,char v){
    int i;
    for(i=0;i<G.vexnum;++i)
        if(G.vexs[i]==v) return i;
    return -1;
}

Status CreateDG(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造有向图G。
    int i,j,k;
    VertexType v1,v2;
    printf("输入顶点数G.vexnum:");
    scanf("%d",&G.vexnum);
    printf("输入边数G.arcnum:");
    scanf("%d",&G.arcnum);
    getchar();
    for(i=0;i<G.vexnum;i++){
        printf("输入顶点G.vexs[%d]:",i);
        scanf("%c",&G.vexs[i]);
        getchar();
    }//构造顶点向量
    for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
        for(j=0;j<G.vexnum;++j){
            G.arcs[i][j].adj=INFINITY;//{adj,info}
            G.arcs[i][j].info=NULL;
        }
    for(k=0;k<G.arcnum;++k)//构造邻接矩阵
    {
        printf("输入第%d条边vi、vj:\n",k+1);
        scanf("%c %c",&v1,&v2);//输入一条边依附的顶点
        getchar();
        i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
        G.arcs[i][j].adj=1;//弧<v1,v2>的权值
        //G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
    }
    return OK;
}//CreateDG

Status CreateDN(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造有向网G。
    int i,j,k,w;
    VertexType v1,v2;
    printf("输入顶点数G.vexnum:");
    scanf("%d",&G.vexnum);
    printf("输入边数G.arcnum:");
    scanf("%d",&G.arcnum);
    getchar();
    for(i=0;i<G.vexnum;i++){
        printf("输入顶点G.vexs[%d]:",i);
        scanf("%c",&G.vexs[i]);
        getchar();
    }//构造顶点向量
    for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
        for(j=0;j<G.vexnum;++j){
            G.arcs[i][j].adj=INFINITY;//{adj,info}
            G.arcs[i][j].info=NULL;
        }
    for(k=0;k<G.arcnum;++k)//构造邻接矩阵
    {
        printf("输入第%d条边vi、vj和权值w(int):\n",k+1);
        scanf("%c %c %d",&v1,&v2,&w);//输入一条边依附的顶点及权值
        getchar();
        i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
        G.arcs[i][j].adj=w;//弧<v1,v2>的权值
        //G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
    }
    return OK;
}//CreateDN

Status CreateUDG(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造无向图G。
    int i,j,k;
    VertexType v1,v2;
    printf("输入顶点数G.vexnum:");
    scanf("%d",&G.vexnum);
    printf("输入边数G.arcnum:");
    scanf("%d",&G.arcnum);
    getchar();
    for(i=0;i<G.vexnum;i++){
        printf("输入顶点G.vexs[%d]:",i);
        scanf("%c",&G.vexs[i]);
        getchar();
    }//构造顶点向量
    for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
        for(j=0;j<G.vexnum;++j){
            G.arcs[i][j].adj=INFINITY;//{adj,info}
            G.arcs[i][j].info=NULL;
        }
    for(k=0;k<G.arcnum;++k)//构造邻接矩阵
    {
        printf("输入第%d条边vi、vj:\n",k+1);
        scanf("%c %c",&v1,&v2);//输入一条边依附的顶点
        getchar();
        i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
        G.arcs[i][j].adj=1;//弧<v1,v2>的权值
        //G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
    }
    return OK;
}//CreateUDG

Status CreateUDN(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造无向网G。
    int i,j,k,w;
    VertexType v1,v2;
    printf("输入顶点数G.vexnum:");
    scanf("%d",&G.vexnum);
    printf("输入边数G.arcnum:");
    scanf("%d",&G.arcnum);
    getchar();
    for(i=0;i<G.vexnum;i++){
        printf("输入顶点G.vexs[%d]:",i);
        scanf("%c",&G.vexs[i]);
        getchar();
    }//构造顶点向量
    for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
        for(j=0;j<G.vexnum;++j){
            G.arcs[i][j].adj=INFINITY;//{adj,info}
            G.arcs[i][j].info=NULL;
        }
    for(k=0;k<G.arcnum;++k)//构造邻接矩阵
    {
        printf("输入第%d条边vi、vj和权值w(int):\n",k+1);
        scanf("%c %c %d",&v1,&v2,&w);//输入一条边依附的顶点及权值
        getchar();
        i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
        G.arcs[i][j].adj=w;//弧<v1,v2>的权值
        G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
    }
    return OK;
}//CreateUDN

Status CreateGraph(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造图G
    printf("请输入图的种类:0表示DG,1表示DN,2表示UDG,3表示UDN\n");
    scanf("%d",&G.kind);//自定义输入函数,读入一个随机值
    switch(G.kind){
        case  DG:return CreateDG(G);//构造有向图G
        case  DN:return CreateDN(G);//构造有向网G
        case UDG:return CreateUDG(G);//构造无向图G
        case UDN:return CreateUDN(G);//构造无向网G
        default:return ERROR;
    }
}//CreateGraph

void list(MGraph G){
    int i,j;
    printf("输出邻接矩阵:\n");
    for(i=0;i<G.vexnum;++i){
        printf("%c----",G.vexs[i]);
        for(j=0;j<G.vexnum;++j)
            if(G.arcs[i][j].adj==INFINITY)
                printf("%4s","∞");//∞ alt+41438
            else 
                printf("%4d",G.arcs[i][j].adj);
        printf("\n");
    }
}

void ShortestPath_DIJ(MGraph G,int v0,PathMatrix &P,ShortPathTable &D){
    //用Dijkstra算法求有向网的v0顶点到其余顶点v的最短路径p[v]及带权长度D[v]
    int v,w,i,j,min;
    Status final[MAX_VERTEX_NUM];
    for(v=0;v<G.vexnum;++v){
        final[v]=FALSE;
        D[v]=G.arcs[v0][v].adj;
        for(w=0;w<G.vexnum;++w)
            P[v][w]=FALSE;
        if(D[v]<INFINITY){
            P[v][v0]=TRUE;
            P[v][v]=TRUE;
        }
    }
    D[v0]=0;
    final[v0]=TRUE;
    for(i=1;i<G.vexnum;++i){
        min=INFINITY;
        for(w=0;w<G.vexnum;++w)
            if(!final[w])
                if(D[w]<min)
                {
                    v=w;
                    min=D[w];
                }
        final[v]=TRUE;
        for(w=0;w<G.vexnum;++w){
            if(!final[w]&& min < INFINITY&&G.arcs[v][w].adj < INFINITY && (min + G.arcs[v][w].adj < D[w]))
            { /* 修改D[w]和P[w],w∈V-S */
                D[w] = min + G.arcs[v][w].adj;
                for (j = 0; j < G.vexnum; ++j)
                    P[w][j] = P[v][j];
                P[w][w] = TRUE;
            }
        }
    }
    for(i=0;i<G.vexnum;++i){
        if(i!=v0){
            printf("%3c  %3c  ",G.vexs[v0],G.vexs[i]);
            if(D[i]!=INFINITY) printf("%5d  ",D[i]);
            else printf("%5s  ","无");
            printf("(");
            for(j=0;j<G.vexnum;++j)
                if(P[i][j])printf("%c",G.vexs[j]);
            printf(")");
            printf("\n");
        }
    }
}

int main(){
    MGraph G;
    int v0;
    PathMatrix P;
    ShortPathTable D;
    CreateGraph(G);
    list(G);
    printf("输入源点序号v0:\n");
    scanf("%d",&v0);
    printf("输出从源点%d到其余顶点的最短路径如下:\n",v0);
    printf("始点 终点 路径长度 最短路径\n");
    ShortestPath_DIJ(G,v0,P,D);
    printf("\n");
    return 0;
}

2、采用书上第 161 页定义的图的邻接矩阵存储表示,编程实现产生最短路径的的 Floyd 算法。

/*采用书上第 161 页定义的图的邻接矩阵存储表示,编程实现产生最短路径的 Floyd 算法。*/
#include<stdio.h>
#include<stdlib.h>
//#include<limits.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define INFINITY 32767//最大值
#define MAX_VERTEX_NUM 20//最大顶点个数
typedef int Status;
typedef int VRType;
typedef int InfoType;
typedef enum {DG,DN,UDG,UDN}GraphKind;//{有向图,有向网,无向图,无向网}

typedef struct ArcCell{
    VRType adj;//VRType是顶点关系类型。对无权图,用0或1
                //表示相邻否;对带权图,则为权值类型
    InfoType *info;//该弧相关信息的指针
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef char VertexType;
typedef struct{
    VertexType vexs[MAX_VERTEX_NUM];//顶点向量
    AdjMatrix arcs;//邻接矩阵
    int vexnum,arcnum;//图的当前顶点数和弧数
    GraphKind kind;//图的种类标志
}MGraph;

typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int DistancMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

int LocateVex(MGraph G,char v){
    int i;
    for(i=0;i<G.vexnum;++i)
        if(G.vexs[i]==v) return i;
    return -1;
}

Status CreateDG(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造有向图G。
    int i,j,k;
    VertexType v1,v2;
    printf("输入顶点数G.vexnum:");
    scanf("%d",&G.vexnum);
    printf("输入边数G.arcnum:");
    scanf("%d",&G.arcnum);
    getchar();
    for(i=0;i<G.vexnum;i++){
        printf("输入顶点G.vexs[%d]:",i);
        scanf("%c",&G.vexs[i]);
        getchar();
    }//构造顶点向量
    for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
        for(j=0;j<G.vexnum;++j){
            G.arcs[i][j].adj=INFINITY;//{adj,info}
            G.arcs[i][j].info=NULL;
        }
    for(k=0;k<G.arcnum;++k)//构造邻接矩阵
    {
        printf("输入第%d条边vi、vj:\n",k+1);
        scanf("%c %c",&v1,&v2);//输入一条边依附的顶点
        getchar();
        i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
        G.arcs[i][j].adj=1;//弧<v1,v2>的权值
        //G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
    }
    return OK;
}//CreateDG

Status CreateDN(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造有向网G。
    int i,j,k,w;
    VertexType v1,v2;
    printf("输入顶点数G.vexnum:");
    scanf("%d",&G.vexnum);
    printf("输入边数G.arcnum:");
    scanf("%d",&G.arcnum);
    getchar();
    for(i=0;i<G.vexnum;i++){
        printf("输入顶点G.vexs[%d]:",i);
        scanf("%c",&G.vexs[i]);
        getchar();
    }//构造顶点向量
    for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
        for(j=0;j<G.vexnum;++j){
            G.arcs[i][j].adj=INFINITY;//{adj,info}
            if(i==j) G.arcs[i][j].adj=0;
            G.arcs[i][j].info=NULL;
        }
    for(k=0;k<G.arcnum;++k)//构造邻接矩阵
    {
        printf("输入第%d条边vi、vj和权值w(int):\n",k+1);
        scanf("%c %c %d",&v1,&v2,&w);//输入一条边依附的顶点及权值
        getchar();
        i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
        G.arcs[i][j].adj=w;//弧<v1,v2>的权值
        //G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
    }
    return OK;
}//CreateDN

Status CreateUDG(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造无向图G。
    int i,j,k;
    VertexType v1,v2;
    printf("输入顶点数G.vexnum:");
    scanf("%d",&G.vexnum);
    printf("输入边数G.arcnum:");
    scanf("%d",&G.arcnum);
    getchar();
    for(i=0;i<G.vexnum;i++){
        printf("输入顶点G.vexs[%d]:",i);
        scanf("%c",&G.vexs[i]);
        getchar();
    }//构造顶点向量
    for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
        for(j=0;j<G.vexnum;++j){
            G.arcs[i][j].adj=INFINITY;//{adj,info}
            G.arcs[i][j].info=NULL;
        }
    for(k=0;k<G.arcnum;++k)//构造邻接矩阵
    {
        printf("输入第%d条边vi、vj:\n",k+1);
        scanf("%c %c",&v1,&v2);//输入一条边依附的顶点
        getchar();
        i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
        G.arcs[i][j].adj=1;//弧<v1,v2>的权值
        //G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
    }
    return OK;
}//CreateUDG

Status CreateUDN(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造无向网G。
    int i,j,k,w;
    VertexType v1,v2;
    printf("输入顶点数G.vexnum:");
    scanf("%d",&G.vexnum);
    printf("输入边数G.arcnum:");
    scanf("%d",&G.arcnum);
    getchar();
    for(i=0;i<G.vexnum;i++){
        printf("输入顶点G.vexs[%d]:",i);
        scanf("%c",&G.vexs[i]);
        getchar();
    }//构造顶点向量
    for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
        for(j=0;j<G.vexnum;++j){
            G.arcs[i][j].adj=INFINITY;//{adj,info}
            G.arcs[i][j].info=NULL;
        }
    for(k=0;k<G.arcnum;++k)//构造邻接矩阵
    {
        printf("输入第%d条边vi、vj和权值w(int):\n",k+1);
        scanf("%c %c %d",&v1,&v2,&w);//输入一条边依附的顶点及权值
        getchar();
        i=LocateVex(G,v1); j=LocateVex(G,v2);//确定v1和v2在G中位置
        G.arcs[i][j].adj=w;//弧<v1,v2>的权值
        G.arcs[j][i].adj=G.arcs[i][j].adj;//置<v1,v2>的对称弧<v2,v1>
    }
    return OK;
}//CreateUDN

Status CreateGraph(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造图G
    printf("请输入图的种类:0表示DG,1表示DN,2表示UDG,3表示UDN\n");
    scanf("%d",&G.kind);//自定义输入函数,读入一个随机值
    switch(G.kind){
        case  DG:return CreateDG(G);//构造有向图G
        case  DN:return CreateDN(G);//构造有向网G
        case UDG:return CreateUDG(G);//构造无向图G
        case UDN:return CreateUDN(G);//构造无向网G
        default:return ERROR;
    }
}//CreateGraph

void list(MGraph G){
    int i,j;
    printf("输出邻接矩阵:\n");
    for(i=0;i<G.vexnum;++i){
        printf("%c----",G.vexs[i]);
        for(j=0;j<G.vexnum;++j)
            if(G.arcs[i][j].adj==INFINITY)
                printf("%4s","∞");//∞ alt+41438
            else 
                printf("%4d",G.arcs[i][j].adj);
        printf("\n");
    }
}

void ShortestPath_FLOYD(MGraph G, PathMatrix &P, DistancMatrix &D)
{ /* 用Floyd算法求有向网G中各对顶点v和w之间的最短路径P[v][w]及其 */
  /* 带权长度D[v][w]。若P[v][w][u]为TRUE,则u是从v到w当前求得最短 */
  /* 路径上的顶点。算法7.16 */
    int u, v, w, i;
    for (v = 0; v < G.vexnum; v++) /* 各对结点之间初始已知路径及距离 */
        for (w = 0; w < G.vexnum; w++)
        {
            D[v][w] = G.arcs[v][w].adj;
            for (u = 0; u < G.vexnum; u++)
                P[v][w][u] = FALSE;
            if (D[v][w] < INFINITY) /* 从v到w有直接路径 */
            {
                P[v][w][v] = TRUE;
                P[v][w][w] = TRUE;
            }
        }
    for (u = 0; u < G.vexnum; u++)
        for (v = 0; v < G.vexnum; v++)
            for (w = 0; w < G.vexnum; w++)
                if (D[v][u] + D[u][w] < D[v][w]) /* 从v经u到w的一条路径更短 */
                {
                    D[v][w] = D[v][u] + D[u][w];
                    for (i = 0; i < G.vexnum; i++)
                        P[v][w][i] = P[v][u][i] || P[u][w][i];
                }
    printf("输出每一对顶点之间的最短路径长度如下:\n");
    for(v=0;v<G.vexnum;++v){
        printf("%c----",G.vexs[v]);
        for(w=0;w<G.vexnum;++w)
            if(D[v][w]==INFINITY)
                printf("%4s","∞");
            else
                printf("%4d",D[v][w]);
        printf("\n");
    }
    printf("输出每一对顶点之间的最短路径如下:\n");
    for(v=0;v<G.vexnum;++v){
        printf("%c----",G.vexs[v]);
        for(w=0;w<G.vexnum;++w){
            for(u=0;u<G.vexnum;++u)
                if(P[v][w][u])printf("%c",G.vexs[u]);
                else printf("∞");
            printf(" ");
        }
        printf("\n");
    }
}

int main(){
    MGraph G;
    PathMatrix P[MAX_VERTEX_NUM];
    DistancMatrix D;
    CreateGraph(G);
    list(G);
    ShortestPath_FLOYD(G,*P,D);
    printf("\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kethy__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值