zoukankan      html  css  js  c++  java
  • 2019.6.24-2019.6.28(实训数据结构)5.图的邻接矩阵表示

    2019.6.24-2019.6.28(实训数据结构) 书籍:《数据结构项目实训教程》 赵君喆,戴文华

    7.1图的邻接矩阵表示

    开发一个用邻接矩阵构造的图的操作程序,要求兼容有向图、无向图、有向网、无向网的创建和操作,程序的接口见主函数。

    #include<cstdio>
    #include<stdlib.h>
    #include<string.h>
    //#include<cunity>
    #include<iostream>
    #include<string>
    #include<fstream>
    #include<iomanip>
    #include<algorithm>
    using namespace std;
    
    #define OK 1
    #define ERROR -1
    #define OVERFLOW -2
    #define Max 100
    typedef int Status;
    #define INFINITY INT_MAX  //用整型最大值代替无穷 
    #define MAX_VERTEX_NUM 50  //最大顶点个数 
    #define MAX_NAME 6  //顶点字符串的最大长度+1 
    #define MAX_INFO 20 //相关信息字符串的最大长度+1 
    
    typedef int VRType; //顶点关系类型
    typedef char InfoType;  //相关信息类型
    typedef char VertexType[MAX_NAME];  // 顶点类型
    
    typedef struct{
        VRType adj;  //无权图用1或0表示相邻否;带权图在这里表示为权值
        InfoType *info;   //该弧相关信息的指针 
    }ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; 
    
    enum GraphKind{DG,DN,UDG,UDN};
    
    bool visited[MAX_VERTEX_NUM];  //访问标志数组 
    
    struct MGraph{
        VertexType vexs[MAX_VERTEX_NUM];  //顶点向量
        AdjMatrix arcs;  //邻接矩阵
        int vexnum;  //图的当前顶点数
        int arcnum;  //图的当前弧度数
        GraphKind kind;  //图的种类坐标数 
    };
    
    int LocateVex(MGraph G,VertexType v){
        //初始条件:图G存在,u和G顶点有相同特征
        //操作结果:若图G中存在顶点u,则返回该顶点在图中的位置;否则返回-1
        int i;
        for(i=0;i<G.vexnum;i++){
            if(strcmp(v,G.vexs[i])==0){
                return i;
            }
        } 
        return -1;
    } 
    
    Status InsertArc(MGraph &G,VertexType v,VertexType w){
        //初始条件:图G存在,v和w是G中的两个顶点
        //操作结果:在G中增添弧<v,w>,若G为无向,则增添对称弧<w,v>
        int i,l,v1,w1;
        char s[MAX_INFO]; 
        v1=LocateVex(G,v);  //
        w1=LocateVex(G,w);  //
        if(v1<0||w1<0)  //v1,w1的值不合法 
            return ERROR;
        G.arcnum++;  // 弧或边数加1
        if(G.kind%2){  //
            printf("请输入此弧或边的权值:");
            scanf("%d",&G.arcs[v1][w1].adj); 
        } 
        else{  //
            G.arcs[v1][w1].adj=1;
        } 
        printf("是否有该弧边的相关信息(0:无,1:有):");
        scanf("%d",&i);
        fflush(stdin);  // 清除缓冲区中残留的回车字符
        if(i){
            printf("请输入弧的相关信息(少于%d个字符):",MAX_INFO);
            gets(s);
            l=strlen(s);
            if(1){
                G.arcs[v1][w1].info=(char*)malloc((l+1)*sizeof(char));
                strcpy(G.arcs[v1][w1].info,s);
            } 
        } 
        if(G.kind>1){  //无向 
            //指向同一个相关信息 
            G.arcs[w1][v1].adj=G.arcs[v1][w1].adj;
            G.arcs[w1][v1].info=G.arcs[v1][w1].info;
        } 
        return OK;
    }
    
    
    void CreateGraph(MGraph &G){
        //操作结果:采用数组(邻接矩阵)表示法,构造图G
        int i,j,k,arcnum;
        VertexType va,vb;
        
        printf("输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3):");
        scanf("%d",&G.kind);
        printf("请输入图的顶点数和弧度数(以空格作为间隔):");
        scanf("%d%d",&G.vexnum,&arcnum);
        if(G.vexnum>=MAX_VERTEX_NUM-1){
            //若输入顶点数超过图G的最大容量,则以最大容量作为顶点数
            G.vexnum=MAX_VERTEX_NUM-1; 
        } 
        printf("请输入%d个顶点值(少于%d个字符):
    ",G.vexnum,MAX_NAME);
        for(i=0;i<G.vexnum;i++){  //构造顶点向量 
            scanf("%s",G.vexs[i]);
        } 
        for(i=0;i<G.vexnum;i++){  //初始化邻接矩阵 
            for(j=0;j<G.vexnum;j++){
                if(G.kind%2)  //
                    G.arcs[i][j].adj=INFINITY;
                else  //
                    G.arcs[i][j].adj=0;
                G.arcs[i][j].info=NULL;
            }
        } 
        G.arcnum=0;
        printf("请输入%d条弧的弧尾、弧头(以空格作为间隔):
    ",arcnum);
        for(k=0;k<arcnum;k++){  //依次增加弧 
            scanf("%s%s",va,vb);
            InsertArc(G,va,vb);
        }
    } 
    
    void DestroyGraph(MGraph &G){
        //初始条件:图G存在
        //操作结果:销毁图G
        int i,j,k=0;
        if(G.kind%2){  //
            k=INFINITY;  //k为两个顶点之间无边或弧时邻接矩阵元素的值 
        } 
        for(i=0;i<G.vexnum;i++){  //释放弧或边的相关信息 
            if(G.kind<2){  //有向 
                for(j=0;j<G.vexnum;j++){
                    if(G.arcs[i][j].adj!=k){ //有弧 
                        if(G.arcs[i][j].info){  //有相关信息 
                            free(G.arcs[i][j].info);
                            G.arcs[i][j].info=NULL;
                        }
                    }
                }
            }
            else{  //无向 
                for(j=i+1;j<G.vexnum;j++){  //只查上三角元素 
                    if(G.arcs[i][j].adj!=k){  //有边 
                        if(G.arcs[i][j].info){  //有相关信息 
                            free(G.arcs[i][j].info);
                            G.arcs[i][j].info=NULL;
                            G.arcs[j][i].info=NULL;
                        }
                    } 
                } 
            } 
        } 
        G.vexnum=0;  //顶点数为0 
        G.arcnum=0;  //边数为0 
    } 
    
    
    
    Status PutVex(MGraph &G,VertexType v,VertexType value){
        //初始条件:图G存在,v是G中某个顶点
        //操作结果:对v赋新值value
        int k;
        k=LocateVex(G,v) ;  //k为顶点v在图G中的序号
        if(k<0){
            return ERROR;
        } 
        strcpy(G.vexs[k],value);
        return OK;
    }
    
    void InsertVex(MGraph &G,VertexType v){
        //初始条件:图G存在,u和G顶点有相同特征
        //操作结果:在图G中增添新顶点v
        int i,j=0;
        if(G.vexnum>=MAX_VERTEX_NUM-1) //若顶点数已达到最大容量,则不能插入此顶点
            return;
        if(G.kind%2)  //
            j=INFINITY;
        strcpy(G.vexs[G.vexnum],v); //构造新顶点向量
        for(i=0;i<=G.vexnum;i++){
            //初始化新增行、新增列邻接矩阵的值(无边或弧)
            G.arcs[G.vexnum][i].adj=j;
            G.arcs[i][G.vexnum].adj=j;
            //初始化相关信息指针
            G.arcs[G.vexnum][i].info=NULL;
            G.arcs[i][G.vexnum].info=NULL; 
        } 
        G.vexnum++;  //图G的顶点数加1 
    }
    
    Status DeleteVex(MGraph &G,VertexType v){
        //初始条件:图G存在,v是G中的某个顶点
        //操作结果:删除G中顶点v及相关的弧
        int i,j,k;
        VRType m=0;
        if(G.kind%2)  //
            m=INFINITY;
        k=LocateVex(G,v);  // k为待删除顶点v的序号
        if(k<0)  //v不是图G的顶点
            return ERROR;
        for(j=0;j<G.vexnum;j++){
            if(G.arcs[j][k].adj!=m){  //有入弧或边 
                if(G.arcs[j][k].info){  //有相关信息 
                    free(G.arcs[j][k].info);  //释放相关信息 
                }
                G.arcnum--;  //修改弧数 
            }
        } 
        if(G.kind<2)  //有向
            for(j=0;j<G.vexnum;j++){
                if(G.arcs[k][j].adj!=m){  //有出弧 
                    if(G.arcs[k][j].info){  //有相关信息 
                        free(G.arcs[k][j].info);  //释放相关信息 
                    }
                    G.arcnum--;  //修改弧数 
                }
            } 
        for(j=k+1;j<G.vexnum;j++){
            //序号k后面的顶点向量依次前移
            strcpy(G.vexs[j-1],G.vexs[j]); 
        }
        for(i=0;i<G.vexnum;i++){
            for(j=k+1;j<G.vexnum;j++){
                //移动待删除顶点之右的矩阵元素
                G.arcs[i][j-1]=G.arcs[i][j]; 
            }
        }
        for(i=0;i<G.vexnum;i++){
            for(j=k+1;j<G.vexnum;j++){
                //移动待删除顶点之下的矩阵元素
                G.arcs[j-1][i]=G.arcs[j][i]; 
            }
        }
        G.vexnum--;  //更新图的顶点数
        return OK; 
    } 
    
    
    Status DeleteArc(MGraph &G,VertexType v,VertexType w){
        //初始条件:图G存在,v和w是G中的两个顶点
        //操作结果:在G中增删除<v,w>,若G为无向,还需删除对称弧<w,v>
        int v1,w1,j=0;
        if(G.kind%2)  //
            j=INFINITY;
        v1=LocateVex(G,v);  //
        w1=LocateVex(G,w);  //
        if(v1<0||w1<0)  //v1,w1的值不合法 
            return ERROR;
        G.arcs[v1][w1].adj=j;
        if(G.arcs[v1][w1].info){  //有其他信息 
            free(G.arcs[v1][w1].info);
            G.arcs[v1][w1].info=NULL;
        }
        if(G.kind>=2){  //无向,删除对称弧 
            G.arcs[w1][v1].adj=j;
            G.arcs[w1][v1].info=NULL;
        } 
        G.arcnum--;  //弧数-1
        return OK; 
    }
    
    int FirstAdjVex(MGraph G,VertexType v){
        //初始条件:图G存在,v是G中某个顶点
        //操作结果:返回v的第一个邻接顶点的序号;若没有则返回-1
        int i,j=0,k;
        k=LocateVex(G,v);  //k为顶点v在图G中的序号
        if(k<0){  //顶点不存在 
            return -1;
        } 
        if(G.kind%2)  //
            j=INFINITY;
        for(i=0;i<G.vexnum;i++){
            if(G.arcs[k][i].adj!=j)
                return i;
        } 
        return -1;
    }
    
    int NextAdjVex(MGraph G,VertexType v,VertexType w){
        //初始条件:图G存在,v和w是G中某个顶点
        //操作结果:返回w的序号;若没有则返回-1
        int i,j=0,k1,k2;
        k1=LocateVex(G,v);  //k为顶点v在图G中的序号
        k2=LocateVex(G,w);
        if(k1<0||k2<0){  //顶点不存在 
            return -1;
        } 
        if(G.kind%2)  //
            j=INFINITY;
        for(i=k2+1;i<G.vexnum;i++){
            if(G.arcs[k1][i].adj!=j)
                return i;
        } 
        return -1;
    }
    void visitVex(MGraph G,int v){
        cout<<G.vexs[v]<<" ";
    }
    void DFS(MGraph G,int v){
        //操作结果:从第v个顶点出发递归地深度优先遍历图G
        int w;
        visited[v]=true;  //设置访问标志为TURE(已访问) 
        visitVex(G,v);  //访问第v个顶点
        //cout<<"dsssssssssscs"<<endl;
        w=FirstAdjVex(G,G.vexs[v]);
        while(w>=0){
            if(!visited[w]){
                //对v的尚未访问的序号为w的邻接顶点递归调用DFS
                DFS(G,w); 
            }
            w=NextAdjVex(G,G.vexs[v],G.vexs[w]);
        } 
    } 
    
    void DFSTraverse(MGraph G){
        //初始条件:图G存在,Visit是顶点的应用函数
        //操作结果:从第1个顶点起,深度优先遍历图G,并对每个顶点调用函数Visit一次且仅调用一次
        int v;
        for(v=0;v<G.vexnum;v++){
            visited[v]=false;  //访问标志数组初始化(未被访问) 
        } 
        for(v=0;v<G.vexnum;v++){
            if(!visited[v])
                DFS(G,v);  //对尚未访问的顶点v调用DFS 
        } 
    }
    
    typedef int SElemType;
    typedef struct QNode{
        SElemType data;
        QNode *next;
    }*QueuePtr;
    struct LinkQueue{
        QueuePtr front,rear;//队头、队尾指针 
    };
    Status InitQueue(LinkQueue &Q){
        if(!(Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode)))){
            exit(OVERFLOW);
        }
        Q.front->next=NULL;
        return OK; 
    } 
    Status EnQueue(LinkQueue &Q,SElemType e){
        QueuePtr p;
        if(!(p=(QueuePtr)malloc(sizeof(QNode)))){
            exit(OVERFLOW);
        }
        p->data=e;
        p->next=NULL;
        Q.rear->next=p;
        Q.rear=p;
        return OK;
    }
    SElemType DeQueue(LinkQueue &Q,SElemType e){
        QueuePtr p;
        if(Q.front==Q.rear){
            return ERROR;
        }
        p=Q.front->next;
        e=p->data;
        Q.front->next=p->next;
        if(Q.rear==p){
            Q.rear=Q.front;
        }
        free(p);
        return OK;
    }
    Status QueueEmpty(LinkQueue Q){
        if(Q.front==Q.rear)
            return 1;
        else
            return 0;
    }
    
    
    void BFSTraverse(MGraph G){
        //初始条件:图G存在,Visit是顶点的应用函数
        //操作结果:从第1个顶点起,广度优先非递归遍历图G,并对每个顶点调用函数Visit一次且仅调用一次
        int u,v,w;
        LinkQueue Q;  //使用辅助队列Q和访问标志数组visited 
        for(v=0;v<G.vexnum;v++){
            visited[v]=false;  // 置初值 
        } 
        InitQueue(Q);  //置空的辅助队列Q
        for(v=0;v<G.vexnum;v++){
            if(!visited[v]){  //尚未访问 
                visited[v]=1;  //设置访问标志为TRUE(已访问)
                visitVex(G,v);
                EnQueue(Q,v);  //v入队列
                while(!QueueEmpty(Q)){  //队列不为空 
                    DeQueue(Q,u);  //队头元素出队并置为u
                    w=FirstAdjVex(G,G.vexs[u]);
                    while(w>=0){
                        if(!visited[w]){
                            //w为u的尚未访问的邻接顶点的序号
                            visited[w]=1;
                            visitVex(G,w);
                            EnQueue(Q,w); 
                        }
                        w=NextAdjVex(G,G.vexs[u],G.vexs[w]);
                    } 
                } 
            }
        } 
    }
    
    void Display(MGraph G){
        //操作结果:输出邻接矩阵存储表示的图
        int i,j;
        char s[7];
        switch(G.kind){
            case DG:
                strcpy(s,"有向图");
                break;
            case DN:
                strcpy(s,"有向网");
                break;
            case UDG:
                strcpy(s,"无向图");
                break;
            case UDN:
                strcpy(s,"无向网");
        } 
        printf("%d个顶点%d条边或弧的%s。顶点依次是:",G.vexnum,G.arcnum,s);
        for(i=0;i<G.vexnum;i++)  //输出G.vexs
            printf("%s ",G.vexs[i]);
        printf("
    G.arcs.adj:
    ");  //输出G.arcs.adj
        for(i=0;i<G.vexnum;i++){
            for(j=0;j<G.vexnum;j++){
                printf("%lld  ",G.arcs[i][j].adj);
            }
            printf("
    ");
        } 
        printf("G.arcs.info:
    ");  //输出G.arcs.info
        printf("顶点1(弧尾) 顶点2(弧头) 该边或弧的信息: 
    ");
        for(i=0;i<G.vexnum;i++){
            if(G.kind<2){
                for(j=0;j<G.vexnum;j++){  //有向 
                    if(G.arcs[i][j].adj>0&&G.arcs[i][j].adj<INFINITY){
                        printf("%5s %11s %s
    ",G.vexs[i],G.vexs[j],G.arcs[i][j].info);
                    }
                }
            }
            else{  //无向,输出上三角元素 
                for(j=i+1;j<G.vexnum;j++){  //有向 
                    if(G.arcs[i][j].adj>0&&G.arcs[i][j].adj<INFINITY){
                        printf("%5s %11s %s
    ",G.vexs[i],G.vexs[j],G.arcs[i][j].info);
                    }
                }
            } 
        } 
    }
    
    
    int main(){
        int choose;
        MGraph G;
        
        CreateGraph(G);
        VertexType v,w,value;
        cout<<"                            欢迎来到邻接矩阵构造系统!!!!!" <<endl; 
        cout<<"                                请按以下数字操作" <<endl; 
        cout<<"----------------------------------1.输出图信息----------------------------------"<<endl;
        cout<<"----------------------------------2.查找顶点号----------------------------------"<<endl;
        cout<<"----------------------------------3.插入顶点------------------------------------"<<endl;
        cout<<"----------------------------------4.删除顶点------------------------------------"<<endl;
        cout<<"----------------------------------5.修改顶点值----------------------------------"<<endl;
        cout<<"----------------------------------6.增加弧--------------------------------------"<<endl;
        cout<<"----------------------------------7.删除弧--------------------------------------"<<endl;
        cout<<"----------------------------------8.深度优先遍历--------------------------------"<<endl;
        cout<<"----------------------------------9.广度优先遍历--------------------------------"<<endl; 
        cout<<"----------------------------------0.退出程序------------------------------------"<<endl<<endl;
        choose=-1;
        while(choose!=0){
            cout<<"--------------------------------------------------------------------------------"<<endl;
            cout<<"请选择:"<<endl;
            cin>>choose; 
            switch(choose){
                case 0:                       
                    cout<<"您已经成功退出系统,欢迎您下次再来!"<<endl;
                break;
                case 1: 
                    Display(G); 
                    cout<<"您已经成功输出图信息!"<<endl;                     
                break;
                case 2: 
                    printf("请输入要查询的顶点:
    ");
                    scanf("%s",&v); 
                    printf("顶点%s查询的顶点号为%d
    ",v,LocateVex(G,v));                      
                break;
                case 3:
                    printf("请输入要插入的顶点:
    ");
                    scanf("%s",&v); 
                    InsertVex(G,v);  
                    printf("您已经成功插入顶点!
    ");                    
                break;
                case 4: 
                    printf("请输入要删除的顶点:
    ");
                    scanf("%s",&v); 
                    DeleteVex(G,v);
                    printf("您已经成功删除顶点!
    ");                       
                break;
                case 5: 
                    printf("请输入要修改的顶点:
    ");
                    scanf("%s",&v);
                    printf("请输入要修改的值:
    ");
                    scanf("%s",&value); 
                    PutVex(G,v,value);
                    printf("您已经成功修改顶点值!
    ");                     
                break;
                case 6: 
                    printf("请输入要增加弧的两个的顶点(以空格分隔):
    ");
                    scanf("%s%s",&v,&w);
                    InsertArc(G,v,w); 
                    printf("您已经成功增加弧!
    ");                     
                break;
                case 7: 
                    printf("请输入要删除弧的两个的顶点(以空格分隔):
    ");
                    scanf("%s%s",&v,&w); 
                    DeleteArc(G,v,w);
                    printf("您已经成功删除弧!
    ");                       
                break;
                case 8: 
                    DFSTraverse(G) ;
                    printf("您已经成功深度优先遍历!
    ");                      
                break;
                case 9: 
                    BFSTraverse(G);  
                    printf("您已经成功广度优先遍历!
    ");                     
                break;
            }
        }    
        return 0;
    }
  • 相关阅读:
    窗口看门狗(WWDG):神舟IV实验
    RTC实验:神舟IV
    C语言运算符优先级
    PWM输出:神舟IV验证
    独立看门狗(IWDG):神舟IV实验
    ADC 转换:神舟IV实验
    输入捕获模式简介
    输入捕获:神舟IV实验
    #ifndef 百度百科
    DAC:神舟IV实验
  • 原文地址:https://www.cnblogs.com/zhying99/p/11083931.html
Copyright © 2011-2022 走看看