图的基本操作【严蔚敏】
来源:互联网 发布:电脑制作漫画软件 编辑:程序博客网 时间: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
- 图的基本操作【严蔚敏】
- 图的基本操作
- 图的基本操作
- 图的基本操作
- 图的基本操作
- 图的基本操作
- 图的基本操作
- 图的基本操作
- *图的基本操作*
- 图的基本操作
- 图的基本操作
- 图的基本操作
- 图的基本操作
- 队列的基本操作【严蔚敏】
- 栈的基本操作【严蔚敏】
- 图基本操作的实现
- 【数据结构】图的基本操作
- 图的基本、常见操作
- java.lang.UnsatisfiedLinkError: com.android.tools.fd.runtime.IncrementalClassLoader$DelegateClassLo
- CodeForces 643 B.Bear and Two Paths(构造)
- mybatis查询,sql语句没问题但是查不出结果
- 二叉树的三种非递归遍历
- 视频码流分析工具
- 图的基本操作【严蔚敏】
- 蓝桥杯入门训练 序列求和 JAVA
- P1067 多项式输出
- java中MD5加密
- 提示框消息
- Batch Normalization
- unit2.9部署 ftp 文件共享服务
- java收集Exception信息
- SHELL脚本