//*******************************************引入头文件*********************************************
#include <stdio.h>   //使用了标准库函数 
#include <stdlib.h>  //使用了动态内存分配函数 
#include "SqQueue.cpp" //由于广度优先遍历要使用队列,而图中的顶点插入删除少访问多,故引入一个已写好的顺序队列 

//******************************************自定义符号常量******************************************* 

#define OVERFLOW -2         //内存溢出错误常量
#define ILLEGAL -1          //非法操作错误常量 
#define OK 1                //表示操作正确的常量 
#define ERROR 0             //表示操作错误的常量

//******************************************自定义数据类型********************************************

typedef int Status;       //用typedef给int起个别名,也便于程序的维护 
typedef float ElemType;   //用typedef给float起个别名,也便于程序的维护

//-------------图的数组(邻接矩阵)存储表示

#define INFINITY        65535     //最大值 ∞
#define MAX_VERTEX_NUM  20          //最大顶点个数
typedef enum {DG,DN,UDG,UDN} GraphKind;  //(有向图,有向网,无向图,无向网)
typedef int VRType;
typedef int VertexType;

typedef struct ArcCell{
    VRType   adj;   //VRType是顶点关系类型。对无权图,用1或0,表示相邻与否,对带权图,则为权值类型 
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; 

typedef struct{
    VertexType vexs[MAX_VERTEX_NUM];    //顶点向量
    AdjMatrix  arcs;     //邻接矩阵
    int vexnum,arcnum;   //图当前的定点数和弧数
    GraphKind  kind;     //图的种类标志 
}MGraph; 

//*********************************************图的主要操作********************************************  

//------------------------------------1.图的创建(构造) ----------------------------------------------
int LocateVex(MGraph G, int v){  //顶点定位函数 
    for(int i=0; i<=G.vexnum; ++i)
        if(G.vexs[i]==v)  
            return i;  //若找到结点返回i 
    return -1;  //否则返回-1,表示没有找到 
}//LocateVex

/*说明:图变网,加权值,改距离    有向变无向 ,置邻接矩阵   反之也对 
                                       加权值  0,1变 ∞ 
                       有向图 <------------------------------> 有向网      
                          |            去权值  ∞变 0,1          | 
                          |                                      |
              去对称矩阵  |  置对称矩阵             去对称矩阵   |   置对称矩阵
                          |                                      |
                          |            加权值  0,1变 ∞          |
                       无向图 <------------------------------> 无向网
                                       去权值  ∞变 0,1
*/ 
Status CreateUDN(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造无向网G
    VertexType v1,v2;
    int w,i,j;
    printf("请依次输入无向网G的顶点数,弧数,用逗号隔开\n");
    scanf("%d,%d",&G.vexnum,&G.arcnum);
    printf("请依次输入无向网G的顶点名称,用空格隔开\n"); 
    for(int i=0;i<G.vexnum;++i)
        scanf("%d",&G.vexs[i]);   //构造各顶点向量 
    for(int i=0;i<G.vexnum;++i)
        for(int j=0;j<G.vexnum;++j)
            G.arcs[i][j].adj=INFINITY; 
    printf("请依次输入无向网G每条弧依附的两顶点名称及权值,输完一组按回车\n"); 
    for(int k=0;k<G.arcnum;++k){ //构造邻接矩阵 
        scanf("%d",&v1);
        scanf("%d",&v2);
        scanf("%d",&w); 
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);     //确定v1,v2在G中的位置 
        G.arcs[i][j].adj=w;
        G.arcs[j][i]=G.arcs[i][j];  //置<v1,v2>的对称弧<v2,v1> 
    }//for
    return OK; 
}// CreateUDN

Status CreateUDG(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造无向图G 
    VertexType v1,v2;
    int i,j;
    printf("请依次输入无向图G的顶点数,弧数,用逗号隔开\n");
    scanf("%d,%d",&G.vexnum,&G.arcnum);
    printf("请依次输入无向图G的顶点名称,用空格隔开\n"); 
    for(int i=0;i<G.vexnum;++i)
        scanf("%d",&G.vexs[i]);   //构造各顶点向量 
    for(int i=0;i<G.vexnum;++i)
        for(int j=0;j<G.vexnum;++j)  //预置邻接矩阵 
            G.arcs[i][j].adj=0; 
    printf("请依次输入无向图G每条弧依附的两顶点名称,输完一组按回车\n"); 
    for(int k=0;k<G.arcnum;++k){ //构造邻接矩阵 
        scanf("%d",&v1);
        scanf("%d",&v2);
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);     //确定v1,v2在G中的位置 
        G.arcs[i][j].adj=1;
        G.arcs[j][i]=G.arcs[i][j];  //置<v1,v2>的对称弧<v2,v1> 
    }//for
    return OK; 
}// CreateUDG

Status CreateDN(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造有向网G 
    VertexType v1,v2;
    int w,i,j;
    printf("请依次输入有向网G的顶点数,弧数,用逗号隔开\n");
    scanf("%d,%d",&G.vexnum,&G.arcnum);
    printf("请依次输入有向网G的顶点名称,用空格隔开\n"); 
    for(int i=0;i<G.vexnum;++i)
        scanf("%d",&G.vexs[i]);   //构造各顶点向量 
    for(int i=0;i<G.vexnum;++i)
        for(int j=0;j<G.vexnum;++j)
            G.arcs[i][j].adj=INFINITY;  
    printf("请依次输入有向网G每条弧依附的两顶点名称及权值,输完一组按回车\n"); 
    for(int k=0;k<G.arcnum;++k){ //构造邻接矩阵 
        scanf("%d",&v1);
        scanf("%d",&v2);
        scanf("%d",&w); 
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);     //确定v1,v2在G中的位置 
        G.arcs[i][j].adj=w;
    }//for
    return OK; 
}// CreateDN

Status CreateDG(MGraph &G){
    //采用数组(邻接矩阵)表示法,构造有向图G 
    VertexType v1,v2;
    int i,j;
    printf("请依次输入有向图G的顶点数,弧数,用逗号隔开\n");
    scanf("%d,%d",&G.vexnum,&G.arcnum);
    printf("请依次输入有向图G的顶点名称,用空格隔开\n"); 
    for(int i=0;i<G.vexnum;++i)
        scanf("%d",&G.vexs[i]);   //构造各顶点向量 
    for(int i=0;i<G.vexnum;++i)
        for(int j=0;j<G.vexnum;++j)
            G.arcs[i][j].adj=0; 
    printf("请依次输入有向图G每条弧依附的两顶点名称,输完一组按回车\n"); 
    for(int k=0;k<G.arcnum;++k){ //构造邻接矩阵 
        scanf("%d",&v1);
        scanf("%d",&v2);
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);     //确定v1,v2在G中的位置 
        G.arcs[i][j].adj=1;
    }//for
    return OK; 
}// CreateDG

Status CreateGraph(MGraph &G){  //总函数 
    //采用数组(邻接矩阵)表示法,构造图G
    printf("请输入您想构造的图的类型:有向图,有向网,无向图,无向网,分别对应0,1,2,3):");
    int temp; 
    scanf("%d",&temp);  //输入所要构造图的类型
    G.kind=(GraphKind)temp;
    switch((GraphKind)temp){
        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

//---------------------------------2.邻接矩阵的输出 ----------------------------------------------
Status PrintAdjMatrix(MGraph G){  //打印某个图的邻接矩阵 
    //采用数组(邻接矩阵)表示法,构造图G
    for(int i=0;i<G.vexnum;i++){
        for(int j=0;j<G.vexnum;j++)
            if(G.arcs[i][j].adj==INFINITY)  
                printf("  ∞ ");
            else 
                printf(" %3d ", G.arcs[i][j].adj);
        printf("\n\n");
    }  
}//PrintAdjMatrix

//------------------------------------3.图的遍历 ----------------------------------------------
int FirstAdjVex(MGraph G,VertexType v){
    //求顶点v在图G中的第一个邻接点
    int i,j=0,k;
    k=LocateVex(G,v);  //v是顶点,不是序号!需要定位 
    if(G.kind==DN||G.kind==UDN)  //若是网
       j=INFINITY;
    for(i=0;i<G.vexnum;++i)
       if(G.arcs[k][i].adj!=j)
           return i;       //若找到则返回i 
    return -1;             //若未找到返回-1 
}//FirstAdjVex

int NextAdjVex(MGraph G,VertexType v,VertexType w){
    //求顶点v在图G中相对于邻接点w的下一个邻接点 
    int i,j=0,k1,k2;
    k1=LocateVex(G,v);  //v是顶点,不是序号!需要定位  
    k2=LocateVex(G,w);  //w是顶点,不是序号!需要定位 
    if(G.kind==DN||G.kind==UDN)  //若是网
       j=INFINITY;
    for(i=k2+1;i<G.vexnum;++i)
       if(G.arcs[k1][i].adj!=j)
           return i;       //若找到则返回i 
    return -1;             //若未找到返回-1  
}//NextAdjVex

//-----------------------深度优先遍历DFS-----------------------------
typedef enum { TRUE=1 , FALSE=0 } Boolean; 
Boolean visited[MAX_VERTEX_NUM];    //访问标志数组 
Status (*VisitFunc)(int v);         //函数变量 

Status Print(int v){  //元素访问函数 
    printf(" %3d ",v);
    return OK;
}//Print

void DFSTraverse(MGraph G,Status (*Visit)(int v)){
    //对图G作深度优先遍历,调用Visit()函数访问结点
    void DFS(MGraph G,int v);  //函数声明 
    VisitFunc=Visit;         //使用全局变量VisitFunc,使DFS不必设函数指针参数 
    for(int v=0;v<G.vexnum;++v)
        visited[v]=FALSE;    //预置标志数组
    for(int v=0;v<G.vexnum;++v)
       if(!visited[v])   //若该顶点未被访问 
           DFS(G,v); 
}//DFSTraverse


void DFS(MGraph G,int v){
    //从第v个顶点出发递归地深度优先遍历图G
    visited[v]=TRUE;  //先将访问标志数组该元素的访问标志改为True 
    //注意,序号v从0开始,所以序号v总比第v个顶点在图中的位置少1 
    VisitFunc(G.vexs[v]);     //访问第v个顶点  注意:v是序号,不是顶点! 
    for(int w=FirstAdjVex(G,G.vexs[v]);w>=0;w=NextAdjVex(G,G.vexs[v],G.vexs[w])){  //v是序号,不是顶点!
        if(!visited[w])
            DFS(G,w);   //对v的尚未访问的邻接点w递归调用DFS 
    }//for
}//DFS

//----------------广度优先遍历 (需要使用队列)BFS------------ 
//说明:队列的相关代码包含在"SqQueue.cpp"中,关于队列的详细方法请阅读该文件 
void BFSTraverse(MGraph G,Status (*Visit)(int v)){
    //按广度优先非递归遍历图G,使用辅助队列Q和访问标志数组visited
    SqQueue Q; 
    for(int v=0;v<G.vexnum;++v)
        visited[v]=FALSE;     //预置标志数组
    InitQueue_Sq(Q);          //置空辅助队列Q
    for(int v=0;v<G.vexnum;++v)
        if(!visited[v]){        //v尚未访问 
            visited[v]=TRUE;  
            Visit(G.vexs[v]);   //访问第v顶点
            EnQueue_Sq(Q,v);    //v入队列 
            while(!QueueEmpty_Sq(Q)){    //队列不空 
                DeQueue_Sq(Q,v);      //队头元素出队并置为u
                for(int w=FirstAdjVex(G,G.vexs[v]);w>=0;w=NextAdjVex(G,G.vexs[v],G.vexs[w])){ 
                     if(!visited[w]){  //w为v尚未访问的邻接顶点 
                          visited[w]=TRUE;  
                          Visit(G.vexs[w]);   //访问第w顶点 
                     }//if 
                }//for 
            }//while 
        }//if
}//BFSTraverse

//------------------------------------ 4.最小生成树 ----------------------------------------------

//-------------------辅助数组的定义------------------------------- 
struct Record{
    VertexType adjvex;   //顶点 
    VRType     lowcost;  //最低代价 
}closedge[MAX_VERTEX_NUM];

int minimum(Record closedge[]){
       int reserve=65535,min;
       for(int i=1;i<MAX_VERTEX_NUM;i++)
          if(closedge[i].lowcost<reserve&&closedge[i].lowcost>0){  //没有访问过但是存在路径
              reserve=closedge[i].lowcost;
              min=i;
          }//if
       return min;
}//minimum

void MiniSpanTree_PRIM(MGraph G,VertexType u){   //普里姆算法求最小生成树 
    //用普里姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边
    //记录从定点集U到V-U的代价最小的边的辅助数组定义
    int k=LocateVex(G,u);
    for(int j=0;j<G.vexnum;++j)  //辅助数组初始化
        if(j!=k){
           closedge[j].adjvex=u;
           closedge[j].lowcost=G.arcs[k][j].adj;  //{adjvex, lowcost}
        }//if
    closedge[k].lowcost=0;     //初始,U={u} 
    printf("最小生成树各条边:\n顶点    权值    顶点  \n");  
    for(int i=1;i<G.vexnum;++i){
        k=minimum(closedge);  //求出T的下一个结点:第k顶点
        //此时closedge[k].lowcost= MIN{ closedge[vi].lowcost | closedge[vi].lowcost>0, vi ∈V-U} 
        printf(" %2d <--- %2d ---> %2d \n",closedge[k].adjvex,closedge[k].lowcost,G.vexs[k]);   //输出生成树的边及其权值 
        closedge[k].lowcost = 0;   //第k顶点并入U集
        for(int j=1;j<G.vexnum;++j)
            if(G.arcs[k][j].adj < closedge[j].lowcost){  //新顶点并入U后重新选择最小边(更新最小边信息)
                closedge[j].adjvex=G.vexs[k];
                closedge[j].lowcost=G.arcs[k][j].adj; 
            }//if
    }//for    
}//MiniSpanTree_PRIM 

//------------------------------------ 5.最短路径 ---------------------------------------------- 
//---------------------------迪斯特拉算法辅助数组的定义--------------------------------
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];

void ShortestPath_DIJ(MGraph G,int v0,PathMatrix &P,ShortPathTable &D){  //用迪斯特拉算法求有向图G最短路径 
    //用Dijkstra算法求有向图G的顶点v0顶点到其余顶点v的最短路径P[v]及其带权长度D[v]
    //若P[v][w]为TRUE,则w是从v0到v当前求得最小路径上的顶点
    //final[v]为TRUE当且仅当v∈S,即已经求得v0到v的最短路径
    int i,v,w,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][w]=TRUE;
        }//if     
    }//for
    D[v0]=0;
    final[v0]=TRUE;    //初始化,v0顶点属于S集
    //开始主循环,每次求得v0到某个顶点v的最短路径,并加v到S集 
    for(i=0;i<G.vexnum;++i){   //其余G.vexnum-1个顶点 
        min=INFINITY;      //当前所知离v0顶点最近距离
        for(w=0;w<G.vexnum;++w)
            if(!final[w])  //w顶点在V-S中 
                if(D[w]<min){
                    v=w;        //w顶点离v0顶点更近 
                    min=D[w];
                }//if 
        final[v]=TRUE;     //离v0顶点最近的v加入S集
        for(w=0;w<G.vexnum;++w)  //更新当前最短路径及距离
           if(!final[w]&&(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;    //P[w]=P[v]+[w]
           }//if 
    }//for  
}//ShortestPath_DIJ

//---------------------------弗洛伊德算法辅助数组的定义--------------------------------
typedef int PathMatrix1[MAX_VERTEX_NUM][MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int DistanceMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

void ShortestPath_FLOYD(MGraph G,PathMatrix1 &P,DistanceMatrix &D){  //用弗洛伊德算法求有向网G最短路径 
    //用Floyd算法求有向网G中各对顶点v和w之间的最短路径P[v][w]及其带权长度D[v][w]。
    //若P[v][w][u]为TRUE,则u是从v到w当前求得最短路径上的顶点。
    int v,w,u,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; 
           }//if 
       }//for
    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][v]<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]; 
             }//if 
}//ShortestPath_FLOYD

//-------------------------------主函数-------------------------------
int main(int argc,char *argv[]){
    printf("\n---------------------------------图的邻接矩阵表示-------------------------------\n"); 
    MGraph G; 
    printf("               ----------------------图的建立------------------                \n");
    CreateGraph(G);      //图的创建
    printf("               --------------------图的邻接矩阵----------------                \n\n"); 
    PrintAdjMatrix(G);   //打印邻接矩阵 
    printf("               ----------------------图的遍历------------------                \n");
    printf("深度优先遍历结果:");
    DFSTraverse(G,Print);
    printf("\n广度优先遍历结果:");
    BFSTraverse(G,Print);
    printf("\n");
    if(G.kind==UDN){  //若为无向网,求其最小生成树 
        printf("               -----------------无向网的最小生成树-------------                \n");
        MiniSpanTree_PRIM(G,G.vexs[0]); 
    }//if
    int v0=0;  //源点  
    PathMatrix P;
    PathMatrix1 P1;
    ShortPathTable D;
    DistanceMatrix D1; 
    if(G.kind==DN){ 
        printf("               ------------------有向网的最短路径--------------                \n");
        printf("\t\t\t执行迪斯特拉算法:\n"); 
        ShortestPath_DIJ(G,v0,P,D);
        printf("最短路径数组P[i][j]如下:\n");
        for(int i=0;i<G.vexnum;++i){
            for(int j=0;j<G.vexnum;++j)
                printf(" %3d ",P[i][j]);
            printf("\n");
        }//for
        printf("顶点%d到其他顶点的最短路径如下:\n",v0);
        for(int i=0;i<G.vexnum;++i)
            printf("%d--->%d :%3d\n",v0,G.vexs[i],D[i]);

        printf("\t\t\t执行弗洛伊德算法:\n");
        for(int i=0;i<G.vexnum;++i)
            G.arcs[i][i].adj=0;      //ShortestPath_FLOYD()要求对角线元素为0 
        printf("执行算法前的邻接矩阵如下:\n");
        PrintAdjMatrix(G);
        ShortestPath_FLOYD(G,P1,D1);
        printf("DistanceMatrix矩阵:\n");
        for(int i=0;i<G.vexnum;++i){
            for(int j=0;j<G.vexnum;++j){
                if(D1[i][j])
                   printf("  ∞ ");
                else
                   printf(" %5d ",D1[i][j]);
            }//for   
            printf("\n\n");
        }//for
        printf("\n最短路径的计算结果:\n");
        for(int i=0;i<G.vexnum;++i)
           for(int j=0;j<G.vexnum;++j)
               printf("%d--->%d 最短路径:%d\n",G.vexs[i],G.vexs[j],D1[i][j]);   
        printf("\n最短路径数组P[i][j][k]如下:\n");
        for(int i=0;i<G.vexnum;++i)
            for(int j=0;j<G.vexnum;++j)
                for(int k=0;k<G.vexnum;++k){
                    printf("P[%d][%d][%d]=%d    ",i,j,k,P1[i][j][k]);
                    if((k+1)%3==0)
                       printf("\n");
                }//for
    }//if 
    return 0;
} 

/*--------------------------输入全程记录(便于测试,可直接复制)------------------------------ 

   说明:下面输入的无向图来自教材P174页,可以直接去该页寻找最小生成树正确结果,以便于验证算法正确与否 

---------------------------------图的邻接矩阵表示-------------------------------

               ----------------------图的建立------------------
请输入您想构造的图的类型:有向图,有向网,无向图,无向网,分别对应0,1,2,3):3
请依次输入无向网G的顶点数,弧数,用逗号隔开
6,10
请依次输入无向网G的顶点名称,用空格隔开
1 2 3 4 5 6
请依次输入无向网G每条弧依附的两顶点名称及权值,输完一组按回车
1 2 6
1 4 5
1 3 1
3 2 5
3 4 5
3 5 6
3 6 4
2 5 3
4 6 2
5 6 6
               --------------------图的邻接矩阵----------------

  ∞    6    1    5    ∞   ∞

  6     ∞   5    ∞   3    ∞

  1     5    ∞   5    6    4

  5     ∞   5    ∞   ∞   2

  ∞    3    6    ∞   ∞   6

  ∞    ∞   4    2    6    ∞

               ----------------------图的遍历------------------
深度优先遍历结果:   1    2    3    4    6    5
广度优先遍历结果:   1    2    3    4    5    6
               -----------------无向网的最小生成树-------------
最小生成树各条边:
顶点    权值    顶点
  1 <---  1 --->  3
  3 <---  4 --->  6
  6 <---  2 --->  4
  3 <---  5 --->  2
  2 <---  3 --->  5

--------------------------------
Process exited with return value 0
Press any key to continue . . .

   说明:下面输入的无向图来自教材P188页,可以直接去该页寻找最短路径的正确结果,以便于验证算法正确与否 


---------------------------------图的邻接矩阵表示-------------------------------

               ----------------------图的建立------------------
请输入您想构造的图的类型:有向图,有向网,无向图,无向网,分别对应0,1,2,3):1
请依次输入有向网G的顶点数,弧数,用逗号隔开
6,8
请依次输入有向网G的顶点名称,用空格隔开
0 1 2 3 4 5
请依次输入有向网G每条弧依附的两顶点名称及权值,输完一组按回车
0 5 100
0 4 30
0 2 10
1 2 5
2 3 50
4 3 20
4 5 60
3 5 10
               --------------------图的邻接矩阵----------------

  ∞   ∞   10   ∞   30  100

  ∞   ∞   5    ∞   ∞   ∞

  ∞   ∞   ∞   50   ∞   ∞

  ∞   ∞   ∞   ∞   ∞   10

  ∞   ∞   ∞   20   ∞   60

  ∞   ∞   ∞   ∞   ∞   ∞

               ----------------------图的遍历------------------
深度优先遍历结果:   0    2    3    5    4    1
广度优先遍历结果:   0    2    4    5    1    3
               ------------------有向网的最短路径--------------
                        执行迪斯特拉算法:
最短路径数组P[i][j]如下:
   0    0    0    0    0    0
   0    0    0    0    0    0
   1    0    0    0    0    0
   1    0    0    1    0    0
   1    0    0    0    0    0
   1    0    0    1    0    1
顶点0到其他顶点的最短路径如下:
0--->0 :  0
0--->1 :65535
0--->2 : 10
0--->3 : 50
0--->4 : 30
0--->5 : 60
                        执行弗洛伊德算法:
执行算法前的邻接矩阵如下:
  0    ∞   10   ∞    30   100

  ∞   0    5    ∞    ∞    ∞

  ∞   ∞   0    50    ∞    ∞

  ∞   ∞   ∞   0     ∞   10

  ∞   ∞   ∞   20    0    60

  ∞   ∞   ∞   ∞   ∞    0

DistanceMatrix矩阵:
  0    ∞   ∞   ∞   ∞   ∞

  ∞   0    ∞   ∞   ∞   ∞

  ∞   ∞   0    ∞   ∞   ∞

  ∞   ∞   ∞   0    ∞   ∞

  ∞   ∞   ∞   ∞   0    ∞

  ∞   ∞   ∞   ∞   ∞   0


最短路径的计算结果:
0--->0 最短路径:0
0--->1 最短路径:65535
0--->2 最短路径:10
0--->3 最短路径:65535
0--->4 最短路径:30
0--->5 最短路径:100
1--->0 最短路径:65535
1--->1 最短路径:0
1--->2 最短路径:5
1--->3 最短路径:65535
1--->4 最短路径:65535
1--->5 最短路径:65535
2--->0 最短路径:65535
2--->1 最短路径:65535
2--->2 最短路径:0
2--->3 最短路径:50
2--->4 最短路径:65535
2--->5 最短路径:65535
3--->0 最短路径:65535
3--->1 最短路径:65535
3--->2 最短路径:65535
3--->3 最短路径:0
3--->4 最短路径:65535
3--->5 最短路径:10
4--->0 最短路径:65535
4--->1 最短路径:65535
4--->2 最短路径:65535
4--->3 最短路径:20
4--->4 最短路径:0
4--->5 最短路径:60
5--->0 最短路径:65535
5--->1 最短路径:65535
5--->2 最短路径:65535
5--->3 最短路径:65535
5--->4 最短路径:65535
5--->5 最短路径:0

最短路径数组P[i][j][k]如下:
P[0][0][0]=1    P[0][0][1]=0    P[0][0][2]=0
P[0][0][3]=0    P[0][0][4]=0    P[0][0][5]=0
P[0][1][0]=1    P[0][1][1]=0    P[0][1][2]=0
P[0][1][3]=0    P[0][1][4]=0    P[0][1][5]=0
P[0][2][0]=1    P[0][2][1]=0    P[0][2][2]=1
P[0][2][3]=0    P[0][2][4]=0    P[0][2][5]=0
P[0][3][0]=1    P[0][3][1]=0    P[0][3][2]=0
P[0][3][3]=0    P[0][3][4]=0    P[0][3][5]=0
P[0][4][0]=1    P[0][4][1]=0    P[0][4][2]=0
P[0][4][3]=0    P[0][4][4]=1    P[0][4][5]=0
P[0][5][0]=1    P[0][5][1]=0    P[0][5][2]=0
P[0][5][3]=0    P[0][5][4]=0    P[0][5][5]=1
P[1][0][0]=0    P[1][0][1]=1    P[1][0][2]=0
P[1][0][3]=0    P[1][0][4]=0    P[1][0][5]=0
P[1][1][0]=0    P[1][1][1]=1    P[1][1][2]=0
P[1][1][3]=0    P[1][1][4]=0    P[1][1][5]=0
P[1][2][0]=0    P[1][2][1]=1    P[1][2][2]=1
P[1][2][3]=0    P[1][2][4]=0    P[1][2][5]=0
P[1][3][0]=0    P[1][3][1]=1    P[1][3][2]=0
P[1][3][3]=0    P[1][3][4]=0    P[1][3][5]=0
P[1][4][0]=0    P[1][4][1]=1    P[1][4][2]=0
P[1][4][3]=0    P[1][4][4]=0    P[1][4][5]=0
P[1][5][0]=0    P[1][5][1]=1    P[1][5][2]=0
P[1][5][3]=0    P[1][5][4]=0    P[1][5][5]=0
P[2][0][0]=0    P[2][0][1]=0    P[2][0][2]=1
P[2][0][3]=0    P[2][0][4]=0    P[2][0][5]=0
P[2][1][0]=0    P[2][1][1]=0    P[2][1][2]=1
P[2][1][3]=0    P[2][1][4]=0    P[2][1][5]=0
P[2][2][0]=0    P[2][2][1]=0    P[2][2][2]=1
P[2][2][3]=0    P[2][2][4]=0    P[2][2][5]=0
P[2][3][0]=0    P[2][3][1]=0    P[2][3][2]=1
P[2][3][3]=1    P[2][3][4]=0    P[2][3][5]=0
P[2][4][0]=0    P[2][4][1]=0    P[2][4][2]=1
P[2][4][3]=0    P[2][4][4]=0    P[2][4][5]=0
P[2][5][0]=0    P[2][5][1]=0    P[2][5][2]=1
P[2][5][3]=0    P[2][5][4]=0    P[2][5][5]=0
P[3][0][0]=0    P[3][0][1]=0    P[3][0][2]=0
P[3][0][3]=1    P[3][0][4]=0    P[3][0][5]=0
P[3][1][0]=0    P[3][1][1]=0    P[3][1][2]=0
P[3][1][3]=1    P[3][1][4]=0    P[3][1][5]=0
P[3][2][0]=0    P[3][2][1]=0    P[3][2][2]=0
P[3][2][3]=1    P[3][2][4]=0    P[3][2][5]=0
P[3][3][0]=0    P[3][3][1]=0    P[3][3][2]=0
P[3][3][3]=1    P[3][3][4]=0    P[3][3][5]=0
P[3][4][0]=0    P[3][4][1]=0    P[3][4][2]=0
P[3][4][3]=1    P[3][4][4]=0    P[3][4][5]=0
P[3][5][0]=0    P[3][5][1]=0    P[3][5][2]=0
P[3][5][3]=1    P[3][5][4]=0    P[3][5][5]=1
P[4][0][0]=0    P[4][0][1]=0    P[4][0][2]=0
P[4][0][3]=0    P[4][0][4]=1    P[4][0][5]=0
P[4][1][0]=0    P[4][1][1]=0    P[4][1][2]=0
P[4][1][3]=0    P[4][1][4]=1    P[4][1][5]=0
P[4][2][0]=0    P[4][2][1]=0    P[4][2][2]=0
P[4][2][3]=0    P[4][2][4]=1    P[4][2][5]=0
P[4][3][0]=0    P[4][3][1]=0    P[4][3][2]=0
P[4][3][3]=1    P[4][3][4]=1    P[4][3][5]=0
P[4][4][0]=0    P[4][4][1]=0    P[4][4][2]=0
P[4][4][3]=0    P[4][4][4]=1    P[4][4][5]=0
P[4][5][0]=0    P[4][5][1]=0    P[4][5][2]=0
P[4][5][3]=0    P[4][5][4]=1    P[4][5][5]=1
P[5][0][0]=0    P[5][0][1]=0    P[5][0][2]=0
P[5][0][3]=0    P[5][0][4]=0    P[5][0][5]=1
P[5][1][0]=0    P[5][1][1]=0    P[5][1][2]=0
P[5][1][3]=0    P[5][1][4]=0    P[5][1][5]=1
P[5][2][0]=0    P[5][2][1]=0    P[5][2][2]=0
P[5][2][3]=0    P[5][2][4]=0    P[5][2][5]=1
P[5][3][0]=0    P[5][3][1]=0    P[5][3][2]=0
P[5][3][3]=0    P[5][3][4]=0    P[5][3][5]=1
P[5][4][0]=0    P[5][4][1]=0    P[5][4][2]=0
P[5][4][3]=0    P[5][4][4]=0    P[5][4][5]=1
P[5][5][0]=0    P[5][5][1]=0    P[5][5][2]=0
P[5][5][3]=0    P[5][5][4]=0    P[5][5][5]=1

--------------------------------
Process exited with return value 0
Press any key to continue . . .   

*/

2.0

#include <stdio.h>
#include <stdlib.h>

#define MAX_VEX_NUM 20
#define INFINITY -1
// 顶点访问标志类型声明 
typedef enum {UNVISITED=0, VISITED=1} visit_t;
// 采用邻接矩阵表示法的图类型定义 
// 这里假设:顶点的信息为 unsigned int类型;边的信息 也为 unsigned int类型, 1表示有边, 0 表示无边。 
typedef struct
{
    unsigned int vertex[MAX_VEX_NUM];
    unsigned int arcs[MAX_VEX_NUM][MAX_VEX_NUM];
    int vex_num, arc_num;
} m_graph_t;

// 输出图的邻接矩阵 
void print_graph(m_graph_t g)
{
    int i, j;

    for (i=0; i<g.vex_num; i++) {
        for (j=0; j<g.vex_num; j++)
            printf("%3d", g.arcs[i][j]);
        printf("\n");
    }
}

// 求图g中顶点v的第一个邻接点,若存在,则返回该邻接点在图中的位置(>=0);否则返回-1。 
int first_adj(m_graph_t g, int v)
{
    int w = 0;
    while ((w<g.vex_num) && (g.arcs[v][w]==0)) w++;
    if (w==g.vex_num) return -1;
    else return w;
}

// 求图g中顶点v的相对于邻接点w的下一个邻接点,若存在,则返回该邻接点在图中的位置(>=0);否则返回-1。 
int next_adj(m_graph_t g, int v, int w)
{
    int u = w+1;
    while ((u<g.vex_num) && (g.arcs[v][u]==0)) u++;
    if (u==g.vex_num) return -1;
    else return u;
}

// 深度优先搜索遍历 
visit_t visited[MAX_VEX_NUM];
void depth_first(m_graph_t g, int v)
{
    int w;
    visited[v] = VISITED;
    printf("%3d",g.vertex[v]);
    for (w=first_adj(g, v); w >= 0; w=next_adj(g, v, w)) 
        if (!visited[w]) depth_first(g, w);
}
void depth_first_traverse(m_graph_t g)
{
    int v;

    for (v=0;v<g.vex_num;v++) visited[v] = UNVISITED;
    for (v=0;v<g.vex_num;v++) 
        if (!visited[v]) depth_first(g, v);
}


// 队列的存储结构及基本操作 
typedef unsigned int queue_elem_t;
// typedef int queue_elem_t;
typedef enum {EMPTY, FULL, READY} status_t;
typedef struct
{
     queue_elem_t *data;
     int front;
     int rear;
     int queue_len;
     status_t status;
} queue;
typedef queue *queue_t;

queue_t init_queue(int len)
{
     queue_t q = (queue_t)malloc(sizeof(queue));
     if (!q) {
          printf("Heap full.\n");
          exit(-1);
     }
     q->data = (queue_elem_t *)malloc(sizeof(queue_elem_t) * len);
     if (!q->data) {
          printf("Heap full.\n");
          exit(-1);
     }
     q->front = q->rear = 0;
     q->queue_len = len;
     q->status = EMPTY;

     return q;
}

queue_t destroy_queue(queue_t q)
{
     if (q) {
          free(q->data);
          free(q);
     }

     return NULL;
}

int is_empty(queue_t q)
{
     return (q->status==EMPTY);
}

void enqueue(queue_t q, queue_elem_t data)
{
     if (!q) {
          printf("You need init queue before using it.\n");
          exit(-1);
     }
     if (q->status != FULL) {
          q->data[q->rear] = data;
          q->rear = (q->rear + 1) % q->queue_len;
          if (q->rear == q->front)
               q->status = FULL;
          else
               q->status = READY;
     }

}

queue_elem_t dequeue(queue_t q)
{
     queue_elem_t data;

     if (!q) {
          printf("You need init queue before using it.\n");
          exit(-1);
     }
     if (q->status != EMPTY) {
          data = q->data[q->front];
          q->front = (q->front + 1) % q->queue_len;
          if (q->front == q->rear)
               q->status = EMPTY;
          else
               q->status = READY;
     }

     return data;
}

queue_elem_t get_front(queue_t q)
{
     return q->data[q->front];
}

void visit_front(queue_t q, void (*do_front)(queue_elem_t *))
{
     if (q->status != EMPTY) 
          do_front(&(q->data[q->front]));
}

void traverse_queue(queue_t q, void (*do_data)(queue_elem_t *))
{
     int front;
     if (q->status != EMPTY) {
          front = q->front;
          do {
               do_data(&(q->data[front]));
               front = (front + 1) % q->queue_len;
          } while (front != q->rear);
     }
}

// 广度优先搜索遍历 
void breadth_first_traverse(m_graph_t g)
{
     visit_t visited[MAX_VEX_NUM];
     int u, v, w;
     queue_t q = init_queue(g.vex_num);

     for (v=0;v<g.vex_num;v++) visited[v] = UNVISITED;
     for (v=0;v<g.vex_num;v++) 
            if (!visited[v]) {
                visited[v] = VISITED;
                printf("%3d", g.vertex[v]);
                enqueue(q, v);
                while (!is_empty(q)) {
                    u = dequeue(q);
                    for (w=first_adj(g, u); w!=-1; w=next_adj(g, u, w))
                        if (!visited[w]) {
                            visited[w] = VISITED;
                            printf("%3d", g.vertex[w]);
                            enqueue(q, w);
                        } //if 
                } // while
            } // if
     destroy_queue(q);
}

// 顶点定位函数 
int LocateVex(m_graph_t *g, unsigned int v){
    int i;
    for (i = 0; i <= g->vex_num; ++i){
        if(g->vertex[i]==v) return i;
    } 
    return -1;
}

// 无向图构造函数 
void create_UDG(m_graph_t *g)
{ //采用数组(邻接矩阵)表示法,构造无向网g。
    int i, j, k;
    unsigned int v1, v2; 
    printf("请输入图的顶点数和边数:");
    scanf("%d,%d", &g->vex_num, &g->arc_num); 
    printf("请输入%d个顶点的信息:\n", g->vex_num);
    for (i = 0; i < g->vex_num; ++i) scanf("%d", &g->vertex[i]); //构造顶点向量
    for (i = 0; i < g->vex_num; ++i) //初始化邻接矩阵
        for (j = 0; j < g->vex_num; ++j) g->arcs[i][j] = 0;
    printf("请输入%d条边的信息:", g->arc_num);
    for (k = 0; k < g->arc_num; ++k) { //构造邻接矩阵
        printf("\n第%d条边(输入该边所依附的两个顶点):", k+1);
        scanf("%d,%d",&v1, &v2);    //输入一条边依附的顶点
        i = LocateVex(g, v1); j = LocateVex(g, v2); //确定v1和v2在G中位置
        g->arcs[i][j] = 1;  
        g->arcs[j][i] = g->arcs[i][j]; //置<v1, v2>的对称边<v2, v1>
    }
    return;
}

/*

       1
      / \
     /   \
    2     3
   / \   / \
  4   5 6---7 
   \ /
    8

*/

int main()
{
/*
    m_graph_t g = {
        {1, 2, 3, 4, 5, 6, 7, 8}, // vertex
        {{  0,  1,  1,  0,  0,  0,  0,  0}, // arcs
         {  1,  0,  0,  1,  1,  0,  0,  0},
         {  1,  0,  0,  0,  0,  1,  1,  0},
         {  0,  1,  0,  0,  0,  0,  0,  1},
         {  0,  1,  0,  0,  0,  0,  0,  1},
         {  0,  0,  1,  0,  0,  0,  1,  0},
         {  0,  0,  1,  0,  0,  1,  0,  0},
         {  0,  0,  0,  1,  1,  0,  0,  0}},
        8, // vex_num
        9 // arc_num
    };
*/
    m_graph_t g;

    create_UDG(&g);  // 调用创建无向图的函数 

    print_graph(g); printf("\n");
    depth_first_traverse(g); printf("\n");
    breadth_first_traverse(g); printf("\n");

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值