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个字符):\n",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条弧的弧尾、弧头(以空格作为间隔):\n",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("\nG.arcs.adj:\n");  //输出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("\n");
    } 
    printf("G.arcs.info:\n");  //输出G.arcs.info
    printf("顶点1(弧尾) 顶点2(弧头) 该边或弧的信息: \n");
    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\n",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\n",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("请输入要查询的顶点:\n");
                scanf("%s",&v); 
                printf("顶点%s查询的顶点号为%d\n",v,LocateVex(G,v));                      
            break;
            case 3:
                printf("请输入要插入的顶点:\n");
                scanf("%s",&v); 
                InsertVex(G,v);  
                printf("您已经成功插入顶点!\n");                    
            break;
            case 4: 
                printf("请输入要删除的顶点:\n");
                scanf("%s",&v); 
                DeleteVex(G,v);
                printf("您已经成功删除顶点!\n");                       
            break;
            case 5: 
                printf("请输入要修改的顶点:\n");
                scanf("%s",&v);
                printf("请输入要修改的值:\n");
                scanf("%s",&value); 
                PutVex(G,v,value);
                printf("您已经成功修改顶点值!\n");                     
            break;
            case 6: 
                printf("请输入要增加弧的两个的顶点(以空格分隔):\n");
                scanf("%s%s",&v,&w);
                InsertArc(G,v,w); 
                printf("您已经成功增加弧!\n");                     
            break;
            case 7: 
                printf("请输入要删除弧的两个的顶点(以空格分隔):\n");
                scanf("%s%s",&v,&w); 
                DeleteArc(G,v,w);
                printf("您已经成功删除弧!\n");                       
            break;
            case 8: 
                DFSTraverse(G) ;
                printf("您已经成功深度优先遍历!\n");                      
            break;
            case 9: 
                BFSTraverse(G);  
                printf("您已经成功广度优先遍历!\n");                     
            break;
        }
    }    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhying99/p/11083931.html