//图的基本运算算法 #include <stdio.h> #include <malloc.h> //图的两种存储结构 #define INF 32767 //定义∞ #define MAXV 100 //最大顶点个数 typedef char InfoType; //以下定义邻接矩阵类型 typedef struct { int no; //顶点编号 InfoType info; //顶点其他信息 } VertexType; //顶点类型 typedef struct { int edges[MAXV][MAXV]; //邻接矩阵数组 int n,e; //顶点数,边数 VertexType vexs[MAXV]; //存放顶点信息 } MatGraph; //完整的图邻接矩阵类型 //以下定义邻接表类型 typedef struct ANode { int adjvex; //该边的邻接点编号 struct ANode *nextarc; //指向下一条边的指针 int weight; //该边的相关信息,如权值(用整型表示) } ArcNode; //边节点类型 typedef struct Vnode { InfoType info; //顶点其他信息 int count; //存放顶点入度,仅仅用于拓扑排序 ArcNode *firstarc; //指向第一条边 } VNode; //邻接表头节点类型 typedef struct { VNode adjlist[MAXV]; //邻接表头节点数组 int n,e; //图中顶点数n和边数e } AdjGraph; //完整的图邻接表类型 //------------------------------------------------------------ //----邻接矩阵的基本运算算法---------------------------------- //------------------------------------------------------------ void CreateMat(MatGraph &g,int A[MAXV][MAXV],int n,int e) //创建图的邻接矩阵 { int i,j; g.n=n; g.e=e; for (i=0;i<g.n;i++) for (j=0;j<g.n;j++) g.edges[i][j]=A[i][j]; } void DispMat(MatGraph g) //输出邻接矩阵g { int i,j; for (i=0;i<g.n;i++) { for (j=0;j<g.n;j++) if (g.edges[i][j]!=INF) printf("%4d",g.edges[i][j]); else printf("%4s","∞"); printf("\n"); } } //------------------------------------------------------------ //------------------------------------------------------------ //----邻接表的基本运算算法------------------------------------ //------------------------------------------------------------ void CreateAdj(AdjGraph *&G,int A[MAXV][MAXV],int n,int e) //创建图的邻接表 { int i,j; ArcNode *p; G=(AdjGraph *)malloc(sizeof(AdjGraph)); for (i=0;i<n;i++) //给邻接表中所有头节点的指针域置初值 G->adjlist[i].firstarc=NULL; for (i=0;i<n;i++) //检查邻接矩阵中每个元素 for (j=n-1;j>=0;j--) if (A[i][j]!=0 && A[i][j]!=INF) //存在一条边 { p=(ArcNode *)malloc(sizeof(ArcNode)); //创建一个节点p p->adjvex=j; p->weight=A[i][j]; p->nextarc=G->adjlist[i].firstarc; //采用头插法插入节点p G->adjlist[i].firstarc=p; } G->n=n; G->e=n; } void DispAdj(AdjGraph *G) //输出邻接表G { ArcNode *p; for (int i=0;i<G->n;i++) { p=G->adjlist[i].firstarc; printf("%3d: ",i); while (p!=NULL) { printf("%3d[%d]→",p->adjvex,p->weight); p=p->nextarc; } printf("∧\n"); } } void DestroyAdj(AdjGraph *&G) //销毁图的邻接表 { ArcNode *pre,*p; for (int i=0;i<G->n;i++) //扫描所有的单链表 { pre=G->adjlist[i].firstarc; //p指向第i个单链表的首节点 if (pre!=NULL) { p=pre->nextarc; while (p!=NULL) //释放第i个单链表的所有边节点 { free(pre); pre=p; p=p->nextarc; } free(pre); } } free(G); //释放头节点数组 }int visited[MAXV]; //全局数组 void PathAll1(AdjGraph *G,int u,int v,int path[],int d) //输出图G中从顶点u到v的所有简单路径 { ArcNode *p; int j,w; d++; path[d]=u; //路径长度d增1,将当前顶点添加到路径中 visited[u]=1; if (u==v && d>0) //找到终点 { for (j=0;j<=d;j++) printf("%3d",path[j]); printf("\n"); visited[u]=0; return; } p=G->adjlist[u].firstarc; //p指向顶点u的第一个相邻点 while (p!=NULL) { w=p->adjvex; //w为u的相邻点编号 if (visited[w]==0 ) //若该顶点未标记访问,则递归访问之 PathAll1(G,w,v,path,d); p=p->nextarc; //找u的下一个相邻点 } visited[u]=0; } void PathAll2(AdjGraph *G,int u,int v,int l,int path[],int d) //输出图G中从顶点u到v的长度为l的所有简单路径,d是到当前为止已走过的路径长度,调用时初值为-1 { int w,i; ArcNode *p; visited[u]=1; d++; path[d]=u; //路径长度d增1,将当前顶点添加到路径中 if (u==v && d==l) //满足条件,输出一条路径 { for (i=0;i<=d;i++) printf("%3d",path[i]); printf("\n"); visited[u]=0; return; } p=G->adjlist[u].firstarc; //p指向顶点u的第一个相邻点 while (p!=NULL) { w=p->adjvex; //w为顶点u的相邻点 if (visited[w]==0) //若该顶点未标记访问,则递归访问之 PathAll2(G,w,v,l,path,d); p=p->nextarc; //找u的下一个相邻点 } visited[u]=0; //取消访问标记,以使该顶点可重新使用 } int ShortPath(AdjGraph *G,int u,int v,int path[]) //求顶点u到顶点v(u≠v)的最短路径 { struct { int vno; //当前顶点编号 int level; //当前顶点的层次 int parent; //当前顶点的当一个节点编号 } qu[MAXV]; //定义顺序非循环队列 int front=-1,rear=-1,k,lev,i,j; ArcNode *p; visited[u]=1; rear++; //顶点u已访问,将其入队 qu[rear].vno=u; qu[rear].level=0; //根节点层次置为1 qu[rear].parent=-1; while (front<rear) //队非空则执行 { front++; k=qu[front].vno; //出队顶点k lev=qu[front].level; if (k==v) //若顶点k为终点 { i=0; //在队列中前推从一条正向路径 j=front; //该路径存放在path中 while (j!=-1) { path[lev-i]=qu[j].vno; //将最短路径存入path中 j=qu[j].parent; i++; } return lev; //找到顶点v,返回其层次 } p=G->adjlist[k].firstarc; //p指向顶点k的第一个相邻点 while (p!=NULL) //依次搜索k的相邻点 { if (visited[p->adjvex]==0) //若未访问过 { visited[p->adjvex]=1; rear++; qu[rear].vno=p->adjvex; //访问过的相邻点进队 qu[rear].level=lev+1; qu[rear].parent=front; } p=p->nextarc; //找顶点k的下一相邻点 } } return -1; //如果未找到顶点v,返回一特殊值-1 }
|
int main() { int i,j; int u=5,v=2,l=3; int path[MAXV]; AdjGraph *G; int A[MAXV][MAXV]={ {0,1,0,1,0,0}, {0,0,1,0,0,0}, {1,0,0,0,0,1}, {0,0,1,0,0,1}, {0,0,0,1,0,0}, {1,1,0,1,1,0}}; int n=6, e=10; CreateAdj(G,A,n,e); //建立图8.21的邻接表 printf("图G的邻接表:\n"); DispAdj(G); printf("(1)从顶点%d到%d的所有路径:\n",u,v); for (i=0;i<n;i++) visited[i]=0; PathAll1(G,u,v,path,-1); printf("(2)从顶点%d到%d的所有长度为%d路径:\n",u,v,l); PathAll2(G,u,v,l,path,-1); printf("(3)从顶点%d到%d的最短路径:\n",u,v); for (i=0;i<n;i++) visited[i]=0; j=ShortPath(G,u,v,path); for (i=0;i<=j;i++) printf("%3d",path[i]); printf("\n"); DestroyAdj(G); return 1; } |