数据结构-图-邻接矩阵

版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/83008491

图是一种较线性表和树更为复杂的数据结构。在线性表中,数据元素之间只有线性关系,每个数据元素只有一个直接前驱和一个直接后继。在树形结构中,数据元素之间有着明显的层次关系,并且每一层上的数据元素可能与下一层中多个元素相关,但只能与上一层中一个元素相关。而在图形结构中,结点之间的关系可以是任意的,图中任意两个数据元素之间都可能相关。因此,图的应用极为广泛。

可以用两个数组分别存储数据元素(顶点)的信息和数据元素之间的关系(边或弧)的信息。

邻接矩阵:行、列各对应一个顶点,若第i行对应顶点到第j列对应的顶点有弧相连则A[i][j]=1,否则为0.

辅助宏的定义:

#define OK         1
#define ERROR      0
#define TRUE       1
#define FALSE      0
#define OVERFLOW  -1
#define UNDERFLOW -2
#define maxn 100
#define INFINITY  32767  //最大值 一定要很大
#define MAX_INFO  50
#define MVNUM     100

typedef int    Status;
typedef char VertexType;
typedef char InfoType;
typedef enum   {DG,DN,UDG,UDN} GraphKind; //图类型 有向图,无向图, 有向网,无向网
 

弧的存储结构定义:

typedef struct ArcType {//弧的定义
   double adj; //邻接数,0、1或w、无穷大
   InfoType *Info; //弧的附加信息
}ArcType;

图的数组表示存储结构定义:

//图的数组表示存储结构定义
typedef struct{
   VertexType *vexs; //顶点信息
   ArcType **arcs; //邻接矩阵
   int vexnum,arcnum; //顶点数 弧数
   GraphKind kind; //图的类型标记
}MGraph;

图的创建.

Status CreateGraph(MGraph &G){
	//图的创建
	//输入图的种类及顶点和边信息构造图G
   scanf("%d",&G.kind); //枚举值DG DN UDG UDN 实际输入0 1 2 3
   switch(G.kind){
      case DG: return CreateDG(G);
      case DN: return CreateDN(G);
	  case UDG:return CreateUDG(G);
	  case UDN:return CreateUDN(G);
	  default :return ERROR;
   }
}

建立无向网G.

Status CreateUDN(MGraph &G){
	//建立无向网G
   int IncInfo,i,j,k;
   double w;
   char s[MAX_INFO];
   VertexType v1,v2;
   scanf("%d %d %d",&G.vexnum,&G.arcnum,&IncInfo); //IncInfo为0表弧没有附加信息
   if(!(G.vexs=(VertexType *)malloc(G.vexnum*sizeof(VertexType))))
	   exit(OVERFLOW);
   if(!(G.arcs=(ArcType **)malloc(G.vexnum*sizeof(ArcType *))))
	   exit(OVERFLOW);
   for(i=0;i<G.vexnum;i++){
      if(!(G.arcs[i]=(ArcType *)malloc(G.vexnum*sizeof(ArcType))))
          exit(OVERFLOW);
      scanf(" %c",&G.vexs[i]);
      for(j=0;j<G.vexnum;j++){
	      G.arcs[i][j].adj=INFINITY; //各弧初始化
		  G.arcs[i][j].Info=NULL;
	  }
   }
   for(k=0;k<G.arcnum;k++){
       scanf(" %c %c %lf",&v1,&v2,&w); //输入一边及其权值
       i=LocateVex(G,v1);//确定顶点下标
       j=LocateVex(G,v2);
	   G.arcs[i][j].adj=w;
	   if(IncInfo){
		  scanf(" %s",s);
          int l=strlen(s);
		  if(!(G.arcs[i][j].Info=(InfoType*)malloc((l+1)*sizeof(InfoType))))
               exit(OVERFLOW);
		  strcpy(G.arcs[i][j].Info,s);
          if(!(G.arcs[j][i].Info=(InfoType*)malloc((l+1)*sizeof(InfoType)))) //无向网需要将对称弧的附加信息加入
               exit(OVERFLOW);
          strcpy(G.arcs[j][i].Info,s);
	   }
	   G.arcs[j][i].adj=w; //无向网需要将对称弧的权值加入
   }
   G.arcnum*=2;
   return OK;
}

建立有向网G.

Status CreateUDG(MGraph &G){
	//建立有向网G
   int i,j,k,IncInfo,l;
   double w;
   char s[MAX_INFO];
   VertexType v1,v2;
   scanf("%d %d %d",&G.vexnum,&G.arcnum,&IncInfo);
   if(!(G.vexs=(VertexType *)malloc(G.vexnum*sizeof(VertexType))))
	   exit(OVERFLOW);
   if(!(G.arcs=(ArcType **)malloc(G.vexnum*sizeof(ArcType *))))
	   exit(OVERFLOW);
   for(i=0;i<G.vexnum;i++){
      if(!(G.arcs[i]=(ArcType *)malloc(G.vexnum*sizeof(ArcType))))
          exit(OVERFLOW);
      scanf(" %c",&G.vexs[i]);
      for(j=0;j<G.vexnum;j++){
	      G.arcs[i][j].adj=INFINITY;
		  G.arcs[i][j].Info=NULL;
	  }
   }
   for(k=0;k<G.arcnum;k++){
       scanf(" %c %c %lf",&v1,&v2,&w);
       i=LocateVex(G,v1);
       j=LocateVex(G,v2);
	   G.arcs[i][j].adj=w;
	   if(IncInfo){
		  scanf(" %s",s);
		  l=strlen(s);
		  if(!(G.arcs[i][j].Info=(InfoType *)malloc((l+1)*sizeof(InfoType)))) //开辟空间存附加信息
               exit(OVERFLOW);
		  strcpy(G.arcs[i][j].Info,s);
	   }
   }
   return OK;
}

创建无向图G.

Status CreateDN(MGraph &G){
		//创建无向图G
   int i,j,k;
   VertexType v1,v2;
   scanf("%d %d",&G.vexnum,&G.arcnum);
   if(!(G.vexs=(VertexType *)malloc(G.vexnum*sizeof(VertexType))))
	   exit(OVERFLOW);
   if(!(G.arcs=(ArcType **)malloc(G.vexnum*sizeof(ArcType *))))
	   exit(OVERFLOW);
   for(i=0;i<G.vexnum;i++){
      if(!(G.arcs[i]=(ArcType *)malloc(G.vexnum*sizeof(ArcType))))
          exit(OVERFLOW);
      scanf(" %c",&G.vexs[i]);
      for(j=0;j<G.vexnum;j++){
	       G.arcs[i][j].adj=INFINITY;
	       G.arcs[i][j].Info=NULL;
	  }
   }
   for(k=0;k<G.arcnum;k++){
       scanf(" %c %c",&v1,&v2);
       i=LocateVex(G,v1);
       j=LocateVex(G,v2);
	   G.arcs[i][j].adj=1;
	   G.arcs[j][i].adj=1; //无向图需要加入对称弧
   }
   G.arcnum*=2;//无向图弧数加倍
   return OK;
}

创建有向图G:

Status CreateDG(MGraph &G){
	//创建有向图G
   int i,j,k;
   VertexType v1,v2;
   scanf("%d %d",&G.vexnum,&G.arcnum);
   if(!(G.vexs=(VertexType *)malloc(G.vexnum*sizeof(VertexType))))
	   exit(OVERFLOW);
   if(!(G.arcs=(ArcType **)malloc(G.vexnum*sizeof(ArcType *)))) //开辟邻接矩阵
	   exit(OVERFLOW);
   for(i=0;i<G.vexnum;i++){
        if(!(G.arcs[i]=(ArcType *)malloc(G.vexnum*sizeof(ArcType))))
          exit(OVERFLOW);
        scanf(" %c",&G.vexs[i]);   //输入结点
        for(j=0;j<G.vexnum;j++){
	      G.arcs[i][j].adj=INFINITY;
	      G.arcs[i][j].Info=NULL;
		}
   }
   for(k=0;k<G.arcnum;k++){
	   //输入弧
      scanf(" %c %c",&v1,&v2);
      i=LocateVex(G,v1);
      j=LocateVex(G,v2);
	  G.arcs[i][j].adj=1; //最短路径时要判断大小再赋值
   }
   return OK;
}

若G中存在顶点v 返回v的位置 否则返回-1.

int LocateVex(MGraph M,VertexType v){
	//若G中存在顶点v 返回v的位置 否则返回-1
   for(int i=0;i<M.vexnum;i++)
	   if(M.vexs[i]==v)
		   return i;
   return -1;
}

销毁一个图G.

Status DestroyGraph(MGraph &G){
	//销毁一个图G
	for(int i=0;i<G.vexnum;i++){
	   for(int j=0;j<G.vexnum;j++){
		 if(G.vexs[i]&&G.arcs[i][j].Info) {
		       free(G.arcs[i][j].Info); //销毁附加信息
			   G.arcs[i][j].Info=NULL;
		   }
	   }
	   free(G.arcs[i]); //销毁邻接数组每一行
	   G.arcs[i]=NULL;
	}
    free(G.arcs);//销毁邻接数组
    G.arcs=NULL;
	free(G.vexs);
	G.vexs=NULL;
	G.arcnum=0;
    G.vexnum=0;
    return OK;
}

向图G中插入一个新的结点v.

Status InsertVex(MGraph &G,VertexType v){
	//向图G中插入一个新的结点v
	int i,j;
    G.vexnum++;
    if(!(G.vexs=(VertexType *)realloc(G.vexs,G.vexnum*sizeof(VertexType)))) //结点数组扩充容量
        exit(OVERFLOW);
    G.vexs[G.vexnum-1]=v; //加入结点
    if(!(G.arcs=(ArcType **)realloc(G.arcs,G.vexnum*sizeof(ArcType *))))//邻接矩阵扩充容量
        exit(OVERFLOW);
	for(i=0;i<G.vexnum-1;i++)
        if(!(G.arcs[i]=(ArcType *)realloc(G.arcs[i],G.vexnum*sizeof(ArcType))))
           exit(OVERFLOW);
    i=G.vexnum-1;
	if(!(G.arcs[i]=(ArcType *)malloc(G.vexnum*sizeof(ArcType))))
          exit(OVERFLOW);
	for(j=0;j<G.vexnum;j++){
		//初始化弧
	   G.arcs[i][j].adj=INFINITY;
	   G.arcs[i][j].Info=NULL;
       G.arcs[j][i]=G.arcs[i][j];
	}
    return OK;
}

删除图G中顶点v 及其关联的弧..

Status DeleteVex(MGraph &G,VertexType v){
	//删除图G中顶点v 及其关联的弧
    int j,i=LocateVex(G,v);
	 for(j=0;j<G.vexnum;j++){
	   if(G.arcs[i][j].adj!=INFINITY){
	      G.arcnum--;
		  if(G.arcs[i][j].Info){ //销毁弧
		     free(G.arcs[i][j].Info); //销毁附加信息
	         G.arcs[i][j].Info=NULL;
		  }
		  G.arcs[i][j].adj=INFINITY; //修改度
	   }
	   if(i!=j&&G.vexs[j]&&G.arcs[j][i].adj!=INFINITY){ //销毁对称弧
		  G.arcnum--;
          if(G.arcs[j][i].Info){
		     free(G.arcs[j][i].Info);
	         G.arcs[j][i].Info=NULL;
		  }
		  G.arcs[j][i].adj=INFINITY;
	   }
	}
	 free(G.arcs[i]); //销毁一行邻接矩阵数组
	 G.arcs[i]=NULL;
	 G.vexs[i]=NULL; //顶点赋空
    return OK;
}

向图G中添加弧v,w 如果是无向的,还应该添加w,v.

Status InsertArc(MGraph &G,VertexType v,VertexType w){
	//向图G中添加弧v,w 如果是无向的,还应该添加w,v
   int i=LocateVex(G,v),j=LocateVex(G,w);
   char s[MAX_INFO];
   G.arcnum++;
   if(G.kind==DG||G.kind==DN){//是有向图或者无向图
       G.arcs[i][j].adj=1;
	   G.arcs[i][j].Info=NULL;
       if(G.kind==DN) {
		   //添加对称弧
		  G.arcnum++;
		  G.arcs[j][i].adj=G.arcs[i][j].adj;
	   }
   }
   else if(G.kind==UDG||G.kind==UDN){//是有向网或者无向网
	   scanf("%lf %s",&G.arcs[i][j].adj,s); //添加度与附加信息
	   int l=strlen(s);
	   if(!(G.arcs[i][j].Info=(InfoType*)malloc((l+1)*sizeof(InfoType)))) //为附加信息开辟空间
			  exit(OVERFLOW);
	   strcpy(G.arcs[i][j].Info,s);
       if(G.kind==UDN){//无向网 加入对称弧
		   G.arcnum++;
           if(!(G.arcs[j][i].Info=(InfoType*)malloc((l+1)*sizeof(InfoType))))
			  exit(OVERFLOW);
	       G.arcs[j][i].adj=G.arcs[i][j].adj;
           strcpy(G.arcs[j][i].Info,s);
	   }
   }
   return OK;
}

删除G中的弧v,w 如果G是无向的 还应该删除 w,v.

Status DeleteArc(MGraph &G,VertexType v,VertexType w){
	//删除G中的弧v,w 如果G是无向的 还应该删除 w,v
   int i=LocateVex(G,v),j=LocateVex(G,w);
   G.arcs[i][j].adj=INFINITY;
   G.arcnum--;
   if(G.arcs[i][j].Info){ //销毁附加信息
      free(G.arcs[i][j].Info);
      G.arcs[i][j].Info=NULL;
   }
   if(G.kind==DN||G.kind==UDN){ //是无向的 销毁对称弧
	  G.arcnum--;
      G.arcs[j][i].adj=INFINITY;
	  if(G.arcs[j][i].Info){
	     free(G.arcs[j][i].Info);
         G.arcs[j][i].Info=NULL;
	  }
   }
   return OK;
}

为G中顶点v 赋值为value.

Status PutVex(MGraph &G,VertexType v,VertexType value){
	//为G中顶点v 赋值为value
   int i=LocateVex(G,v);
   if(i>=0)
      G.vexs[i]=value;
   return OK;
}

返回G中 v顶点的第一个邻接点 若没有返回空.

int FirstAdjVex(MGraph G,int v){
	//返回G中 v顶点的第一个邻接点 若没有返回空
	if(v>=0) {//如果找到v顶点
       for(int j=0;j<G.vexnum;j++)
	   if(G.arcs[v][j].adj!=INFINITY)
		   return j;
   }
   return -1;
}

返回G中 w是v顶点的一个邻接点 返回v的临界点w后下一个邻接点 若w是最后一个邻接点 返回空.

int NextAdjVex(MGraph &G,int v,int w){
	//返回G中 w是v顶点的一个邻接点 返回v的临界点w后下一个邻接点 若w是最后一个邻接点 返回空
   int k;
   if(v>=0&&w>=0){
      for(k=w+1;k<G.vexnum;k++)
	    if(G.arcs[v][k].adj!=INFINITY)
		   return k;
   }
   return -1;
}

输出图G的结点数 弧数 图类型 以及所有顶点和其对应的弧.

void PrintGraph(MGraph G){
	//输出图G的结点数 弧数 图类型 以及所有顶点和其对应的弧
    int i,j,n=0;
	for(i=0;i<G.vexnum;i++)
		if(!G.vexs[i]) //去除空节点
			n++;
    printf("结点个数:%d 弧个数:%d  ",G.vexnum-n,G.arcnum);
	if(!(G.vexnum-n))
		printf("空图\n");
	else{
	    switch(G.kind){
	        case DG:
	           printf("有向图\n");
		       break;
	        case DN:
		       printf("无向图\n");
		       break;
	        case UDG:
		       printf("有向网\n");
		       break;
	        case UDN:
		       printf("无向网\n");
		       break;
		}
	    printf("结点:");
        for(i=0;i<G.vexnum;i++)
			if(G.vexs[i])
	           printf("%c ",G.vexs[i]);
        printf("\n");
           for(i=0;i<G.vexnum;i++){
	          for(j=0;j<G.vexnum;j++)
				  if(G.vexs[i]&&G.arcs[i][j].adj!=INFINITY)
			         printf("%c %c %.2f %s\n",G.vexs[i],G.vexs[j],G.arcs[i][j].adj,G.arcs[i][j].Info);
		   }
	}
}

猜你喜欢

转载自blog.csdn.net/baidu_38304645/article/details/83008491