图的基本算法
图主要是DFS+BFS,其他都可变形得到
#include<stdio.h> #include<stdlib.h> #define MAX 200000000//表示节点间不可达 #define NodeNum 50//假设小于50个节点 //有向图算法。无向图与有向图类似 //图的标配 //1.数组(标识是否访问过) //2.存储结构(邻接矩阵/邻接表) //3.访问的数据结构(BFS中队列,非递归DFS中的栈) int path[NodeNum]={0}; int NodeMapIndex[NodeNum]={0};//将字母映射为数字 int Metrix[NodeNum][NodeNum]={0}; int visit[NodeNum]={0};//visit数组(全局,标识是否访问过) int lowCost[NodeNum]={0};//到达每个顶点的最小代价(在Prim与Dijkstra表示的意义不同) int dist[NodeNum][NodeNum]={0};//Floyd存储最点距离 //图的邻接表定义 typedef struct ArcNode { int adjvex; int value;//权值 ArcNode *nextarc; }ArcNode; typedef struct VNode { char data;//图中的顶点数据,当然也可以是整形 ArcNode*firstarc; }VNode,Adjlist[NodeNum]; typedef struct { Adjlist vertices; int vexnum,arcnum; }AlGraph; //创建图-邻接矩阵 int CreateGraph1() { int n,i,j,value; scanf("%d",&n); if(n>0) { for(i=0;i<n;i++) { for(j=0;j<n;j++) { Metrix[i][j]=0; } } while(scanf("%d%d%d",&i,&j,&value)&&i>=0&&i<n&&j>=0&&j<n) { Metrix[i][j]=value; //如果是无向图则需要再加一个节点Metrix[j][i]=value; } return n; } else { puts("节点数不能为负!"); return -1; } } //创建有向图-邻接表 void CreateGraph2(AlGraph &G) { int n,i,j,value; scanf("%d",&n); getchar(); if(n>0) { char ch1,ch2; G.vexnum=n; //创建n个节点 for(i=0;i<n;) { scanf("%c",&ch1); getchar(); if(ch1>='a'&&ch1<='z') { G.vertices[i].data=ch1; G.vertices[i].firstarc=NULL; NodeMapIndex[ch1-'a']=i;//将字母映射为数字 i++; } } //创建弧 G.arcnum=0; while(1) { //输入弧节点 scanf("%c %c %d",&ch1,&ch2,&value); getchar(); if(!(ch1>='a'&&ch1<='z'&&ch2>='a'&&ch2<='z')) { break; } //定位ch1---ch2 ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode)); p->adjvex=NodeMapIndex[ch2-'a']; p->value=value; p->nextarc=G.vertices[NodeMapIndex[ch1-'a']].firstarc; G.vertices[NodeMapIndex[ch1-'a']].firstarc=p; G.arcnum++; //如果是无向图则需要再加一个节点 } } else { puts("节点数不能为负!"); } } //创建无向图-邻接表 void CreateGraph3(AlGraph &G) { int n,i,j,value; scanf("%d",&n); getchar(); if(n>0) { char ch1,ch2; G.vexnum=n; //创建n个节点 for(i=0;i<n;) { scanf("%c",&ch1); getchar(); if(ch1>='a'&&ch1<='z') { G.vertices[i].data=ch1; G.vertices[i].firstarc=NULL; NodeMapIndex[ch1-'a']=i;//将字母映射为数字 i++; } } //创建弧 G.arcnum=0; while(1) { //输入弧节点 scanf("%c %c %d",&ch1,&ch2,&value); getchar(); if(!(ch1>='a'&&ch1<='z'&&ch2>='a'&&ch2<='z')) { break; } //定位ch1--->ch2 ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode)); p->adjvex=NodeMapIndex[ch2-'a']; p->value=value; p->nextarc=G.vertices[NodeMapIndex[ch1-'a']].firstarc; G.vertices[NodeMapIndex[ch1-'a']].firstarc=p; //如果是无向图则需要再加一个节点 //定位ch2--->ch1 p=(ArcNode*)malloc(sizeof(ArcNode)); p->adjvex=NodeMapIndex[ch1-'a']; p->value=value; p->nextarc=G.vertices[NodeMapIndex[ch2-'a']].firstarc; G.vertices[NodeMapIndex[ch2-'a']].firstarc=p; G.arcnum++; } } else { puts("节点数不能为负!"); } } void CrashAlGraph(AlGraph &G) { for(int i=0;i<G.vexnum;i++) { visit[i]=0; } ArcNode*p,*q; for(int i=0;i<G.vexnum;i++) { p=G.vertices[i].firstarc; G.vertices[i].firstarc=NULL; while(p) { q=p; p=p->nextarc; free(q); q=NULL; } } puts("Crashed!"); } void VisitNode(int v) { printf("%c ",'a'+v); } void DFS(AlGraph G,int v) { visit[v]=1; VisitNode(v); ArcNode *p=G.vertices[v].firstarc; for(;p;p=p->nextarc) { int w=p->adjvex; if(visit[w]==0) { DFS(G,w); } } } //非递归DFS类似于树的先序非递归 void DFS2(AlGraph G,int v) { ArcNode*Stack[NodeNum],*p; int top=0; visit[v]=1; VisitNode(v); p=G.vertices[v].firstarc; while(top>0||p) { while(p) { if(visit[p->adjvex]==1) { p=p->nextarc; } else { visit[p->adjvex]=1; VisitNode(p->adjvex); Stack[top++]=p; p=G.vertices[p->adjvex].firstarc; } } if(top>0) { p=Stack[--top]; p=p->nextarc; } } } //广度优先 void BFS(AlGraph G,int v) { int Queue[NodeNum]={0}; int front=0,rear=0; if(visit[v]==0) { Queue[rear++]=v; while(front<rear) { int u=Queue[front++]; visit[u]=1; VisitNode(u); ArcNode *p=G.vertices[u].firstarc; //将所有未访问得临节点入队 for(;p;p=p->nextarc) { int w=p->adjvex; if(visit[w]==0) { Queue[rear++]=w; } } } } } //访问图每个节点 void VisitGraph(AlGraph G) { for(int i=0;i<G.vexnum;i++) { visit[i]=0; } for(int i=0;i<G.vexnum;i++) { if(visit[i]==0) { DFS2(G,i);//BFS(G,i); } } puts(""); for(int i=0;i<G.vexnum;i++) { visit[i]=0; } } //判断 a 到 c 是否有路经-邻接表(a是否可到c) int IsPath1(AlGraph G,char a,char c) { DFS(G,NodeMapIndex[a-'a']);//BFS(G,NodeMapIndex[a-'a']); return visit[ NodeMapIndex[c-'a']]; } //判断 a 到 c 是否有路经-邻接矩阵(可用弗洛伊德算法) //略 //找到a到c所有的路径 void FindPath(AlGraph G,char a,char c,int len) { visit[NodeMapIndex[a-'a']]=1; path[len++]=NodeMapIndex[a-'a']; if(a==c) { for(int i=0;i<len;i++) { printf("%c ",G.vertices[path[i]].data); } puts(""); } else { ArcNode*p=G.vertices[NodeMapIndex[a-'a']].firstarc; for(;p;p=p->nextarc) { int w=p->adjvex; if(visit[w]==0) { FindPath(G,G.vertices[w].data,c,len); } } } visit[NodeMapIndex[a-'a']]=0; } //无向图的连通分量(DFS/BFS)略 //有向图的强连通分量(加点法:a->c且c->a则a,c是同一个连通分量)略 //拓扑排序(邻接表存储) //王道 //(逆邻接表存储略) int TopSort(AlGraph G) { int i=0,j=0,top=0; int Degree[NodeNum]={0}; int Stack[NodeNum]={0}; int SortArr[NodeNum]={0}; ArcNode*p; //计算所有顶点入度 for(i=0;i<G.vexnum;i++) { p=G.vertices[i].firstarc; for(;p;p=p->nextarc) { int w=p->adjvex; Degree[w]++; } } //入度为0入栈 for(i=0;i<G.vexnum;i++) { if(Degree[i]==0) { Stack[top++]=i; } } while(top>0) { int v=Stack[--top]; SortArr[j++]=v; p=G.vertices[v].firstarc; //临接点入度减一为0入栈 for(;p;p=p->nextarc) { if(--Degree[p->adjvex]==0) { Stack[top++]=p->adjvex; } } } if(j<G.vexnum)return 0; else { for(i=0;i<G.vexnum;i++) { VisitNode(SortArr[i]); } puts(""); return 1; } } //DFS在确保含有拓扑序列的条件下用于输出TopSort序列 //王道 //(不能用来判断是否无环) int finish[NodeNum]={0}; int time=0;//递归完成时间(子节点总是先于自己递归完成) void TopDFS(AlGraph G,int v) { visit[v]=1; ArcNode*p=G.vertices[v].firstarc; for(;p;p=p->nextarc) { int w=p->adjvex; if(visit[w]==0) { TopDFS(G,w); } } finish[time++]=v; } //以TopDFS输出拓扑序列 void TopSort2(AlGraph G) { for(int i=0;i<G.vexnum;i++) { visit[i]=0; } for(int i=0;i<G.vexnum;i++) { if(visit[i]==0) { TopDFS(G,i); } } for(int i=time-1;i>=0;i--) { VisitNode(finish[i]); } puts(""); } //判断图是否有环(对每个点DFS,能找到自己则有环) //或者拓扑排序 void LoopDFS(AlGraph G,int u,int& flag) { visit[u]=-1; ArcNode*p=G.vertices[u].firstarc; for(;p;p=p->nextarc) { if(visit[p->adjvex]==0) { LoopDFS(G,p->adjvex,flag); } else if(visit[p->adjvex]==-1)//在返回之前又遇到访问过的节点 { flag=1; } } visit[u]=1; } int IsLoop(AlGraph G)//利用LoopDFS判断是否有环 { int flag=0,u=0; for(int i=0;i<G.vexnum;i++) { visit[i]=0; } for(int i=0;i<G.vexnum;i++) { if(visit[i]==0) { LoopDFS(G,i,flag); } } return flag; } //最小生成树prim int Prim(AlGraph G,int u) { int cost=0; for(int i=0;i<G.vexnum;i++) { lowCost[i]=MAX; visit[i]=0; } lowCost[u]=0; for(int i=0;i<G.vexnum;i++) { int min=MAX; for(int j=0;j<G.vexnum;j++) { if(visit[j]==0&&min>lowCost[j]) { min=lowCost[j]; u=j; } } visit[u]=1; VisitNode(u); cost+=lowCost[u]; ArcNode*p=G.vertices[u].firstarc; for(;p;p=p->nextarc) { int w=p->adjvex; if(visit[w]==0&&lowCost[w]>p->value) { lowCost[w]=p->value; } } } return cost; } //单源最短路Dijkstra(不含负权) //u--->v int Dijkstra(AlGraph G,int u,int v) { //int cost=0; for(int i=0;i<G.vexnum;i++) { lowCost[i]=MAX; visit[i]=0; } lowCost[u]=0; for(int i=0;i<G.vexnum;i++) { int min=MAX; for(int j=0;j<G.vexnum;j++) { if(visit[j]==0&&min>lowCost[j]) { min=lowCost[j]; u=j; } } visit[u]=1; //cost+=lowCost[u]; ArcNode*p=G.vertices[u].firstarc; for(;p;p=p->nextarc) { int w=p->adjvex; //与prim算法不同之处对lowCost修改 if(visit[w]==0&&lowCost[w]>lowCost[u]+p->value) { lowCost[w]=lowCost[u]+p->value; } } } return lowCost[v]; } //任意顶点间最短路 //Floyd(不含负权) void Floyd(AlGraph G) { ArcNode *p; //初始化visit与dist矩阵 for(int i=0;i<G.vexnum;i++) { visit[i]=0; for(int j=0;j<G.vexnum;j++) { dist[i][j]=MAX; } p=G.vertices[i].firstarc; for(;p;p=p->nextarc) { if(dist[i][p->adjvex]>p->value) { dist[i][p->adjvex]=p->value; } } } for(int k=0;k<G.vexnum;k++)//i->j经过k { for(int i=0;i<G.vexnum;i++) { for(int j=0;j<G.vexnum;j++) { if(i!=j&&i!=k&&j!=k&&dist[i][j]>dist[i][k]+dist[k][j]) { dist[i][j]=dist[i][k]+dist[k][j]; } } } //输出dist矩阵 for(int i=0;i<G.vexnum;i++) { for(int j=0;j<G.vexnum;j++) { printf("%10d\t",dist[i][j]); } puts(""); } puts(""); } } int main() { AlGraph G; CreateGraph3(G); VisitGraph(G); //int len=0; //FindPath(G,'a','c',len); //printf("TopSort=%d\n",TopSort(G)); //TopSort2(G); //printf("IsLoop=%d\n",IsLoop(G)); int u=1;printf("Prim=%d\n",Prim(G,u)); printf("Dijkstra=%d\n",Dijkstra(G,u,3)); Floyd(G); CrashAlGraph(G); return 0; }