图的基本算法
图主要是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;
}