图的基本操作【严蔚敏】

来源:互联网 发布:电脑制作漫画软件 编辑:程序博客网 时间:2024/05/20 00:16

图的基本操作:

ADT Graph{    数据对象V:V是具有相同特性的数据元素的集合,称为顶点集。        数据关系R:R={VR}    VR={<v,w>|v,w∈V且P(v,w),<v,w>表示从v到w的弧,        谓词P(v,w)定义了弧<v,w>的意义或信息}    基本操作:    CreateGraph( &G, V, VR )    初始条件:V是图的顶点集,VR是图中弧的集合。    操作结果:按V和VR的定义构造图G。    DestroyGraph( &G )    初始条件:图G存在。    操作结果:销毁图G。    LocateVex( G, u )    初始条件:图G存在,u和G中顶点有相同特征。    操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回其它信息。    GetVex( G, v )    初始条件:图G存在,v是G中某个顶点。    操作结果:返回v的值。    PutVex( &G, v, value )    初始条件:图G存在,v是G中某个顶点。    操作结果:对v赋值value。    FirstAdjVex( G, v )    初始条件:图G存在,v是G中某个顶点。    操作结果:返回v的第一个邻接顶点。若顶点在G中没有邻接顶点,则返回“空”。    NextAdjVex( G, v, w )    初始条件:图G存在,v是G中某个顶点,w是v的邻接顶点。    操作结果:返回v的(相对于w的)下一个邻接顶点。若w是v的最后一个邻接点,则返回“空”。    InsertVex( &G, v )    初始条件:图G存在,v和图中顶点有相同特征。    操作结果:在图G中增添新顶点v。    DeleteVex( &G, v )    初始条件:图G存在,v是G中某个顶点。    操作结果:删除G中顶点v及其相关的弧。    InsertArc( &G, v, w )    初始条件:图G存在,v和w是G中两个顶点。    操作结果:在G中增添弧<v,w>,若G是无向的,则还增添对称弧<v,w>。    DeleteArc( &G, v, w )    初始条件:图G存在,v和w是G中两个顶点。    操作结果:在G中删除弧<v,w>,若G是无向的,则还删除对称弧<v,w>。    DFSTraverse( G, Visit() )    初始条件:图G存在,Visit是顶点的应用函数。    操作结果:对图进行深度优先遍历。在遍历过程中对每个顶点调用函数Visit一次且仅一次。一旦visit()失败,则操作失败。    BFSTraverse( G, Visit() )    初始条件:图G存在,Visit是顶点的应用函数。    操作结果:对图进行广度优先遍历。在遍历过程中对每个顶点调用函数Visit一次且仅一次。一旦visit()失败,则操作失败。}ADT Graph

具体实现【严蔚敏】:

#define MAX_VERTEX_NUM 20 enum GraphKind{DG,DN,AG,AN}; // {有向图,有向网,无向图,无向网} struct ArcNode {   int adjvex; // 该弧所指向的顶点的位置   ArcNode *nextarc; // 指向下一条弧的指针   InfoType *info; // 网的权值指针 }; // 表结点 typedef struct {   VertexType data; // 顶点信息   ArcNode *firstarc; // 第一个表结点的地址,指向第一条依附该顶点的弧的指针 }VNode,AdjList[MAX_VERTEX_NUM]; // 头结点 struct ALGraph {   AdjList vertices;   int vexnum,arcnum; // 图的当前顶点数和弧数   int kind; // 图的种类标志 };

图的数组表示【严蔚敏】:

int LocateVex(MGraph G,VertexType u) { // 初始条件:图G存在,u和G中顶点有相同特征   // 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1   int i;   for(i=0;i<G.vexnum;++i)     if(strcmp(u,G.vexs[i])==0)       return i;   return -1; } Status CreateFAG(MGraph &G) { // 采用数组(邻接矩阵)表示法,由文件构造没有相关信息的无向图G   int i,j,k;   char filename[13];   VertexType va,vb;   FILE *graphlist;   printf("请输入数据文件名(f7-1.dat):");   scanf("%s",filename);   graphlist=fopen(filename,"r");   fscanf(graphlist,"%d",&G.vexnum);   fscanf(graphlist,"%d",&G.arcnum);   for(i=0;i<G.vexnum;++i) // 构造顶点向量     fscanf(graphlist,"%s",G.vexs[i]);   for(i=0;i<G.vexnum;++i) // 初始化邻接矩阵     for(j=0;j<G.vexnum;++j)     {       G.arcs[i][j].adj=0; // 图       G.arcs[i][j].info=NULL; // 没有相关信息     }   for(k=0;k<G.arcnum;++k)   {     fscanf(graphlist,"%s%s",va,vb);     i=LocateVex(G,va);     j=LocateVex(G,vb);     G.arcs[i][j].adj=G.arcs[j][i].adj=1; // 无向图   }   fclose(graphlist);   G.kind=AG;   return OK; } Status CreateDG(MGraph &G) { // 采用数组(邻接矩阵)表示法,构造有向图G   int i,j,k,l,IncInfo;   char s[MAX_INFO],*info;   VertexType va,vb;   printf("请输入有向图G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");   scanf("%d,%d,%d",&G.vexnum,&G.arcnum,&IncInfo);   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)     {       G.arcs[i][j].adj=0; // 图       G.arcs[i][j].info=NULL;  }   printf("请输入%d条弧的弧尾 弧头(以空格作为间隔): \n",G.arcnum);   for(k=0;k<G.arcnum;++k)   {     scanf("%s%s%*c",va,vb);  // %*c吃掉回车符     i=LocateVex(G,va);     j=LocateVex(G,vb);     G.arcs[i][j].adj=1; // 有向图     if(IncInfo)     {       printf("请输入该弧的相关信息(<%d个字符): ",MAX_INFO);       gets(s);       l=strlen(s);       if(l)       {         info=(char*)malloc((l+1)*sizeof(char));         strcpy(info,s);         G.arcs[i][j].info=info; // 有向       }     }   }   G.kind=DG;   return OK; } Status CreateDN(MGraph &G) { // 采用数组(邻接矩阵)表示法,构造有向网G   int i,j,k,w,IncInfo;   char s[MAX_INFO],*info;   VertexType va,vb;   printf("请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");   scanf("%d,%d,%d",&G.vexnum,&G.arcnum,&IncInfo);   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)     {       G.arcs[i][j].adj=INFINITY; // 网       G.arcs[i][j].info=NULL;     }   printf("请输入%d条弧的弧尾 弧头 权值(以空格作为间隔): \n",G.arcnum);   for(k=0;k<G.arcnum;++k)   {     scanf("%s%s%d%*c",va,vb,&w);  // %*c吃掉回车符     i=LocateVex(G,va);     j=LocateVex(G,vb);     G.arcs[i][j].adj=w; // 有向网     if(IncInfo)     {       printf("请输入该弧的相关信息(<%d个字符): ",MAX_INFO);       gets(s);       w=strlen(s);       if(w)       {         info=(char*)malloc((w+1)*sizeof(char));         strcpy(info,s);         G.arcs[i][j].info=info; // 有向       }     }   }   G.kind=DN;   return OK; } Status CreateAG(MGraph &G) { // 采用数组(邻接矩阵)表示法,构造无向图G   int i,j,k,l,IncInfo;   char s[MAX_INFO],*info;   VertexType va,vb;   printf("请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0): ");   scanf("%d,%d,%d",&G.vexnum,&G.arcnum,&IncInfo);   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)     {       G.arcs[i][j].adj=0; // 图       G.arcs[i][j].info=NULL;     }   printf("请输入%d条边的顶点1 顶点2(以空格作为间隔): \n",G.arcnum);   for(k=0;k<G.arcnum;++k)   {     scanf("%s%s%*c",va,vb); // %*c吃掉回车符     i=LocateVex(G,va);     j=LocateVex(G,vb);     G.arcs[i][j].adj=G.arcs[j][i].adj=1; // 无向图     if(IncInfo)     {       printf("请输入该边的相关信息(<%d个字符): ",MAX_INFO);       gets(s);       l=strlen(s);       if(l)       {         info=(char*)malloc((l+1)*sizeof(char));         strcpy(info,s);         G.arcs[i][j].info=G.arcs[j][i].info=info; // 无向       }     }   }   G.kind=AG;   return OK; } Status CreateAN(MGraph &G) { // 采用数组(邻接矩阵)表示法,构造无向网G。算法7.2   int i,j,k,w,IncInfo;   char s[MAX_INFO],*info;   VertexType va,vb;   printf("请输入无向网G的顶点数,边数,边是否含其它信息(是:1,否:0): ");   scanf("%d,%d,%d",&G.vexnum,&G.arcnum,&IncInfo);   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)     {       G.arcs[i][j].adj=INFINITY; // 网       G.arcs[i][j].info=NULL;     }   printf("请输入%d条边的顶点1 顶点2 权值(以空格作为间隔): \n",G.arcnum);   for(k=0;k<G.arcnum;++k)   {     scanf("%s%s%d%*c",va,vb,&w); // %*c吃掉回车符     i=LocateVex(G,va);     j=LocateVex(G,vb);     G.arcs[i][j].adj=G.arcs[j][i].adj=w; // 无向     if(IncInfo)     {       printf("请输入该边的相关信息(<%d个字符): ",MAX_INFO);       gets(s);       w=strlen(s);       if(w)       {         info=(char*)malloc((w+1)*sizeof(char));         strcpy(info,s);         G.arcs[i][j].info=G.arcs[j][i].info=info; // 无向       }     }   }   G.kind=AN;   return OK; } Status CreateGraph(MGraph &G) { // 采用数组(邻接矩阵)表示法,构造图G。算法7.1   printf("请输入图G的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");   scanf("%d",&G.kind);   switch(G.kind)   {     case DG: return CreateDG(G); // 构造有向图     case DN: return CreateDN(G); // 构造有向网     case AG: return CreateAG(G); // 构造无向图     case AN: return CreateAN(G); // 构造无向网     default: return ERROR;   } } void DestroyGraph(MGraph &G) { // 初始条件: 图G存在。操作结果: 销毁图G   int i,j;   if(G.kind<2) // 有向     for(i=0;i<G.vexnum;i++) // 释放弧的相关信息(如果有的话)     {       for(j=0;j<G.vexnum;j++)         if(G.arcs[i][j].adj==1&&G.kind==0||G.arcs[i][j].adj!=INFINITY&&G.kind==1) // 有向图的弧||有向网的弧           if(G.arcs[i][j].info) // 有相关信息           {             free(G.arcs[i][j].info);             G.arcs[i][j].info=NULL;           }     }   else // 无向     for(i=0;i<G.vexnum;i++) // 释放边的相关信息(如果有的话)       for(j=i+1;j<G.vexnum;j++)         if(G.arcs[i][j].adj==1&&G.kind==2||G.arcs[i][j].adj!=INFINITY&&G.kind==3) // 无向图的边||无向网的边           if(G.arcs[i][j].info) // 有相关信息           {             free(G.arcs[i][j].info);             G.arcs[i][j].info=G.arcs[j][i].info=NULL;           }   G.vexnum=0;   G.arcnum=0; } VertexType& GetVex(MGraph G,int v) { // 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值   if(v>=G.vexnum||v<0)     exit(ERROR);   return G.vexs[v]; } 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; } int FirstAdjVex(MGraph G,VertexType v) { // 初始条件: 图G存在,v是G中某个顶点   // 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1   int i,j=0,k;   k=LocateVex(G,v); // k为顶点v在图G中的序号   if(G.kind==DN||G.kind==AN) // 网     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是G中某个顶点,w是v的邻接顶点   // 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号,   //           若w是v的最后一个邻接顶点,则返回-1   int i,j=0,k1,k2;   k1=LocateVex(G,v); // k1为顶点v在图G中的序号   k2=LocateVex(G,w); // k2为顶点w在图G中的序号   if(G.kind==DN||G.kind==AN) // 网     j=INFINITY;   for(i=k2+1;i<G.vexnum;i++)     if(G.arcs[k1][i].adj!=j)       return i;   return -1; } void InsertVex(MGraph &G,VertexType v) { // 初始条件: 图G存在,v和图G中顶点有相同特征   // 操作结果: 在图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做)   int i;   strcpy(G.vexs[G.vexnum],v); // 构造新顶点向量   for(i=0;i<=G.vexnum;i++)   {     if(G.kind%2) // 网     {       G.arcs[G.vexnum][i].adj=INFINITY; // 初始化该行邻接矩阵的值(无边或弧)       G.arcs[i][G.vexnum].adj=INFINITY; // 初始化该列邻接矩阵的值(无边或弧)     }     else // 图     {       G.arcs[G.vexnum][i].adj=0; // 初始化该行邻接矩阵的值(无边或弧)       G.arcs[i][G.vexnum].adj=0; // 初始化该列邻接矩阵的值(无边或弧)     }     G.arcs[G.vexnum][i].info=NULL; // 初始化相关信息指针     G.arcs[i][G.vexnum].info=NULL;   }   G.vexnum+=1; // 图G的顶点数加1 } Status DeleteVex(MGraph &G,VertexType v) { // 初始条件: 图G存在,v是G中某个顶点。操作结果: 删除G中顶点v及其相关的弧   int i,j,k;   VRType m=0;   k=LocateVex(G,v); // k为待删除顶点v的序号   if(k<0) // v不是图G的顶点     return ERROR;   if(G.kind==DN||G.kind==AN) // 网     m=INFINITY;   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==DG||G.kind==DN) // 有向     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 InsertArc(MGraph &G,VertexType v,VertexType w) { // 初始条件: 图G存在,v和W是G中两个顶点   // 操作结果: 在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v>   int i,l,v1,w1;   char *info,s[MAX_INFO];   v1=LocateVex(G,v); // 尾   w1=LocateVex(G,w); // 头   if(v1<0||w1<0)     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%*c",&i);   if(i)   {     printf("请输入该弧或边的相关信息(<%d个字符):",MAX_INFO);     gets(s);     l=strlen(s);     if(l)     {       info=(char*)malloc((l+1)*sizeof(char));       strcpy(info,s);       G.arcs[v1][w1].info=info;     }   }   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; } Status DeleteArc(MGraph &G,VertexType v,VertexType w) { // 初始条件: 图G存在,v和w是G中两个顶点   // 操作结果: 在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v>   int v1,w1;   v1=LocateVex(G,v); // 尾   w1=LocateVex(G,w); // 头   if(v1<0||w1<0) // v1、w1的值不合法     return ERROR;   if(G.kind%2==0) // 图     G.arcs[v1][w1].adj=0;   else // 网     G.arcs[v1][w1].adj=INFINITY;   if(G.arcs[v1][w1].info) // 有其它信息   {     free(G.arcs[v1][w1].info);     G.arcs[v1][w1].info=NULL;   }   if(G.kind>=2) // 无向,删除对称弧<w,v>   {     G.arcs[w1][v1].adj=G.arcs[v1][w1].adj;     G.arcs[w1][v1].info=NULL;   }   G.arcnum--;   return OK; } Boolean visited[MAX_VERTEX_NUM]; // 访问标志数组(全局量) Status(*VisitFunc)(VertexType); // 函数变量 void DFS(MGraph G,int v) { // 从第v个顶点出发递归地深度优先遍历图G。算法7.5   VertexType w1,v1;   int w;   visited[v]=TRUE; // 设置访问标志为TRUE(已访问)   VisitFunc(G.vexs[v]); // 访问第v个顶点   strcpy(v1,GetVex(G,v));   for(w=FirstAdjVex(G,v1);w>=0;w=NextAdjVex(G,v1,strcpy(w1,GetVex(G,w))))     if(!visited[w])       DFS(G,w); // 对v的尚未访问的序号为w的邻接顶点递归调用DFS } void DFSTraverse(MGraph G,Status(*Visit)(VertexType)) { // 初始条件: 图G存在,Visit是顶点的应用函数。算法7.4   // 操作结果: 从第1个顶点起,深度优先遍历图G,并对每个顶点调用函数Visit   //           一次且仅一次。一旦Visit()失败,则操作失败   int v;   VisitFunc=Visit; // 使用全局变量VisitFunc,使DFS不必设函数指针参数   for(v=0;v<G.vexnum;v++)     visited[v]=FALSE; // 访问标志数组初始化(未被访问)   for(v=0;v<G.vexnum;v++)     if(!visited[v])       DFS(G,v); // 对尚未访问的顶点调用DFS   printf("\n"); }

图的邻接表表示【严蔚敏】:

图的数组(邻接矩阵)存储表示 #define INFINITY INT_MAX // 用整型最大值代替∞ #define MAX_VERTEX_NUM 20 // 最大顶点个数 enum GraphKind{DG,DN,AG,AN}; // {有向图,有向网,无向图,无向网} typedef struct {   VRType adj; // 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否;           // 对带权图,则为权值类型   InfoType *info; // 该弧相关信息的指针(可无) }ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; struct MGraph {   VertexType vexs[MAX_VERTEX_NUM]; // 顶点向量   AdjMatrix arcs; // 邻接矩阵   int vexnum,arcnum; // 图的当前顶点数和弧数   GraphKind kind; // 图的种类标志 };
 int LocateVex(ALGraph G,VertexType u) { // 初始条件: 图G存在,u和G中顶点有相同特征   // 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1   int i;   for(i=0;i<G.vexnum;++i)     if(strcmp(u,G.vertices[i].data)==0)       return i;   return -1; } Status CreateGraph(ALGraph &G) { // 采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图)   int i,j,k;   int w; // 权值   VertexType va,vb;   ArcNode *p;   printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");   scanf("%d",&G.kind);   printf("请输入图的顶点数,边数: ");   scanf("%d,%d",&G.vexnum,&G.arcnum);   printf("请输入%d个顶点的值(<%d个字符):\n",G.vexnum,MAX_NAME);   for(i=0;i<G.vexnum;++i) // 构造顶点向量   {     scanf("%s",G.vertices[i].data);     G.vertices[i].firstarc=NULL;   }   if(G.kind==1||G.kind==3) // 网     printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");   else // 图     printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");   for(k=0;k<G.arcnum;++k) // 构造表结点链表   {     if(G.kind==1||G.kind==3) // 网       scanf("%d%s%s",&w,va,vb);     else // 图       scanf("%s%s",va,vb);     i=LocateVex(G,va); // 弧尾     j=LocateVex(G,vb); // 弧头     p=(ArcNode*)malloc(sizeof(ArcNode));     p->adjvex=j;     if(G.kind==1||G.kind==3) // 网     {       p->info=(int *)malloc(sizeof(int));       *(p->info)=w;     }     else       p->info=NULL; // 图     p->nextarc=G.vertices[i].firstarc; // 插在表头     G.vertices[i].firstarc=p;     if(G.kind>=2) // 无向图或网,产生第二个表结点     {       p=(ArcNode*)malloc(sizeof(ArcNode));       p->adjvex=i;       if(G.kind==3) // 无向网       {         p->info=(int*)malloc(sizeof(int));         *(p->info)=w;       }       else         p->info=NULL; // 无向图       p->nextarc=G.vertices[j].firstarc; // 插在表头       G.vertices[j].firstarc=p;     }   }   return OK; } void DestroyGraph(ALGraph &G) { // 初始条件: 图G存在。操作结果: 销毁图G   int i;   ArcNode *p,*q;   G.vexnum=0;   G.arcnum=0;   for(i=0;i<G.vexnum;++i)   {     p=G.vertices[i].firstarc;     while(p)     {       q=p->nextarc;       if(G.kind%2) // 网         free(p->info);       free(p);       p=q;     }   } } VertexType& GetVex(ALGraph G,int v) { // 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值   if(v>=G.vexnum||v<0)     exit(ERROR);   return G.vertices[v].data; } Status PutVex(ALGraph &G,VertexType v,VertexType value) { // 初始条件: 图G存在,v是G中某个顶点   // 操作结果: 对v赋新值value   int i;   i=LocateVex(G,v);   if(i>-1) // v是G的顶点   {     strcpy(G.vertices[i].data,value);     return OK;   }   return ERROR; } int FirstAdjVex(ALGraph G,VertexType v) { // 初始条件: 图G存在,v是G中某个顶点   // 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1   ArcNode *p;   int v1;   v1=LocateVex(G,v); // v1为顶点v在图G中的序号   p=G.vertices[v1].firstarc;   if(p)     return p->adjvex;   else     return -1; } int NextAdjVex(ALGraph G,VertexType v,VertexType w) { // 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点   // 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。   //           若w是v的最后一个邻接点,则返回-1   ArcNode *p;   int v1,w1;   v1=LocateVex(G,v); // v1为顶点v在图G中的序号   w1=LocateVex(G,w); // w1为顶点w在图G中的序号   p=G.vertices[v1].firstarc;   while(p&&p->adjvex!=w1) // 指针p不空且所指表结点不是w     p=p->nextarc;   if(!p||!p->nextarc) // 没找到w或w是最后一个邻接点     return -1;   else // p->adjvex==w     return p->nextarc->adjvex; // 返回v的(相对于w的)下一个邻接顶点的序号 } void InsertVex(ALGraph &G,VertexType v) { // 初始条件: 图G存在,v和图中顶点有相同特征   // 操作结果: 在图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做)   strcpy(G.vertices[G.vexnum].data,v); // 构造新顶点向量   G.vertices[G.vexnum].firstarc=NULL;   G.vexnum++; // 图G的顶点数加1 } Status DeleteVex(ALGraph &G,VertexType v) { // 初始条件: 图G存在,v是G中某个顶点   // 操作结果: 删除G中顶点v及其相关的弧   int i,j;   ArcNode *p,*q;   j=LocateVex(G,v); // j是顶点v的序号   if(j<0) // v不是图G的顶点     return ERROR;   p=G.vertices[j].firstarc; // 删除以v为出度的弧或边   while(p)   {     q=p;     p=p->nextarc;     if(G.kind%2) // 网       free(q->info);     free(q);     G.arcnum--; // 弧或边数减1   }   G.vexnum--; // 顶点数减1   for(i=j;i<G.vexnum;i++) // 顶点v后面的顶点前移     G.vertices[i]=G.vertices[i+1];   for(i=0;i<G.vexnum;i++) // 删除以v为入度的弧或边且必要时修改表结点的顶点位置值   {     p=G.vertices[i].firstarc; // 指向第1条弧或边     while(p) // 有弧     {       if(p->adjvex==j)       {         if(p==G.vertices[i].firstarc) // 待删结点是第1个结点         {           G.vertices[i].firstarc=p->nextarc;           if(G.kind%2) // 网             free(p->info);           free(p);           p=G.vertices[i].firstarc;           if(G.kind<2) // 有向             G.arcnum--; // 弧或边数减1         }         else         {           q->nextarc=p->nextarc;           if(G.kind%2) // 网             free(p->info);           free(p);           p=q->nextarc;           if(G.kind<2) // 有向             G.arcnum--; // 弧或边数减1         }       }       else       {         if(p->adjvex>j)           p->adjvex--; // 修改表结点的顶点位置值(序号)         q=p;         p=p->nextarc;       }     }   }   return OK; } Status InsertArc(ALGraph &G,VertexType v,VertexType w) { // 初始条件: 图G存在,v和w是G中两个顶点   // 操作结果: 在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v>   ArcNode *p;   int w1,i,j;   i=LocateVex(G,v); // 弧尾或边的序号   j=LocateVex(G,w); // 弧头或边的序号   if(i<0||j<0)     return ERROR;   G.arcnum++; // 图G的弧或边的数目加1   if(G.kind%2) // 网   {     printf("请输入弧(边)%s→%s的权值: ",v,w);     scanf("%d",&w1);   }   p=(ArcNode*)malloc(sizeof(ArcNode));   p->adjvex=j;   if(G.kind%2) // 网   {     p->info=(int*)malloc(sizeof(int));     *(p->info)=w1;   }   else     p->info=NULL;   p->nextarc=G.vertices[i].firstarc; // 插在表头   G.vertices[i].firstarc=p;   if(G.kind>=2) // 无向,生成另一个表结点   {     p=(ArcNode*)malloc(sizeof(ArcNode));     p->adjvex=i;     if(G.kind==3) // 无向网     {       p->info=(int*)malloc(sizeof(int));       *(p->info)=w1;     }     else       p->info=NULL;     p->nextarc=G.vertices[j].firstarc; // 插在表头     G.vertices[j].firstarc=p;   }   return OK; } Status DeleteArc(ALGraph &G,VertexType v,VertexType w) { // 初始条件: 图G存在,v和w是G中两个顶点   // 操作结果: 在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v>   ArcNode *p,*q;   int i,j;   i=LocateVex(G,v); // i是顶点v(弧尾)的序号   j=LocateVex(G,w); // j是顶点w(弧头)的序号   if(i<0||j<0||i==j)     return ERROR;   p=G.vertices[i].firstarc; // p指向顶点v的第一条出弧   while(p&&p->adjvex!=j) // p不空且所指之弧不是待删除弧<v,w>   { // p指向下一条弧     q=p;     p=p->nextarc;   }   if(p&&p->adjvex==j) // 找到弧<v,w>   {     if(p==G.vertices[i].firstarc) // p所指是第1条弧       G.vertices[i].firstarc=p->nextarc; // 指向下一条弧     else       q->nextarc=p->nextarc; // 指向下一条弧     if(G.kind%2) // 网       free(p->info);     free(p); // 释放此结点     G.arcnum--; // 弧或边数减1   }   if(G.kind>=2) // 无向,删除对称弧<w,v>   {     p=G.vertices[j].firstarc; // p指向顶点w的第一条出弧     while(p&&p->adjvex!=i) // p不空且所指之弧不是待删除弧<w,v>     { // p指向下一条弧       q=p;       p=p->nextarc;     }     if(p&&p->adjvex==i) // 找到弧<w,v>     {       if(p==G.vertices[j].firstarc) // p所指是第1条弧         G.vertices[j].firstarc=p->nextarc; // 指向下一条弧       else         q->nextarc=p->nextarc; // 指向下一条弧       if(G.kind==3) // 无向网         free(p->info);       free(p); // 释放此结点     }   }   return OK; } Boolean visited[MAX_VERTEX_NUM]; // 访问标志数组(全局量) void(*VisitFunc)(char* v); // 函数变量(全局量) void DFS(ALGraph G,int v) { // 从第v个顶点出发递归地深度优先遍历图G。算法7.5   int w;   VertexType v1,w1;   strcpy(v1,GetVex(G,v));   visited[v]=TRUE; // 设置访问标志为TRUE(已访问)   VisitFunc(G.vertices[v].data); // 访问第v个顶点   for(w=FirstAdjVex(G,v1);w>=0;w=NextAdjVex(G,v1,strcpy(w1,GetVex(G,w))))     if(!visited[w])       DFS(G,w); // 对v的尚未访问的邻接点w递归调用DFS } void DFSTraverse(ALGraph G,void(*Visit)(char*)) { // 对图G作深度优先遍历。算法7.4   int v;   VisitFunc=Visit; // 使用全局变量VisitFunc,使DFS不必设函数指针参数   for(v=0;v<G.vexnum;v++)     visited[v]=FALSE; // 访问标志数组初始化   for(v=0;v<G.vexnum;v++)     if(!visited[v])       DFS(G,v); // 对尚未访问的顶点调用DFS   printf("\n"); }
0 0
原创粉丝点击