//图的邻接矩阵结构
# define maxsize 100
typedef struct
{
int data;
}Vertex;
typedef struct
{
int edges[maxsize][maxsize];//以N阶矩阵存储边的权值
Vertex ver[maxsize];//定义一个顶点的数组
int n,e;//n为顶点的个数,e为边的条数
}MGraph;
//图的邻接表结构
typedef struct ArcNode
{
int adjvex;//边连接的顶点
struct ArcNode *nextarc;//下一条边
}ArcNode;//边结点
typedef struct
{
int data;
ArcNode *firstarc;//顶点的第一条边
}Vertex;
typedef struct
{
Vertex ver[maxsize];
int n,e;
}Graph;
//图的深度优先搜索遍历算法
int visit[maxsize]={0};//因为BFS是递归运算,因此visit必须定义成全局数组
void BFS(Graph *G,int V0)
{
ArcNode *p;
visit[V0]=1;//给已经遍历过的结点修改标志位
p=G->ver[V0].firstarc;//令指针p指向V0结点的第一条边
while(p!=NULL)
{
if(visit[p->adjvex]==0)
BFS(G,p->adjvex);//递归遍历图G
}
}//BFS遍历过程类似于二叉树的先序遍历
//图的广度优先搜索遍历算法
void DFS(Graph *G,int V0)
{
int queue[maxsize],front=0,rear=0;//定义循环队列作为DFS的辅助数据结构
ArcNode *p;
int v;
int visit[maxsize]={0};//注意此处的visit数组定义与BFS的不同
if(V0!=NULL)
{
visit[V0]=1;
rear=(rear+1)%maxsize;//循环队列入队
queue[rear]=V0;
while(rear!=front)
{
front=(front+1)%maxsize;
v=queue[front];
p=G->ver[v].firstarc;
while(p!=NULL)
{
if(visit[p->adjvex]==0)
{
rear=(rear+1)%maxsize;
queue[rear]=p->adjvex;//未遍历的结点入队
}
p=p->nextarc;//p指向第二条边
}
}
}
}//DFS算法类似于二叉树的层次遍历,遍历的最后一个结点一定是离源点最远的一点
//最小生成树(最小代价树)在无向图中求出权值之和最小的一个最大连通子图
//Prim算法
void Prim(MGraph *G,int V0)
{
int lowcost[maxsize],set[maxsize];//lowcost数组表示到结点i的权值,set数组=1表示已经并入当前生成树
int v=V0;
for(int i=0;i<G->n;++i)
{
lowcost[i]=G->edges[v][i];
set[i]=0;
}//初始化这两个数组
set[V0]=1;//将V0并入生成树
int sum=0;
int min,k,INF=100000;//INF比当前任何权值都大,为了求出最小值
for(int i=0;i<G->n-1;++i)//除V0之外循环n-1次
{
min=INF;
for(int j=0;j<G->n;++j)
{
if(set[j]==0&&lowcost[j]<min)
{
min=lowcost[j];
k=j;
}
}//求出当前权值边的最小值
v=k;
set[v]=1;//将求出的权值连接的点并入生成树
sum+=min;//求生成树的总权值
for(int j=0;j<G->n;++j)
{
if(set[j]==0&&lowcost[j]<G->edges[v][j])
G->edges[v][j]=lowcost[j];
}//以v为中间点刷新图中的最小权值
}
}
//克鲁斯卡尔算法,用并查集作为辅助结构(树的双亲存储结构)
typedef struct
{
int a,b;
int w;
}Road;//a,b为边连接的两个顶点,w为权值
int Getroot(int a,int v[])//求根函数
{
while(a!=v[a])
a=v[a];
}
void Kruscal(MGraph *G,Road road[ ])
{
int v[maxsize];//定义并查集
for(int i=0;i<G->n;++i)//并查集初始化
v[i]=i;//此时图中每个顶点的根节点都是自身
sort(road);//给图中边的权值大小按从小到大排序
int a,b,sum=0;
for(int i=0;i<G->n;++i)
{
a=Getroot(road[i].a);
b=Getroot(road[i].b);
if(a!=b)
{
a=v[b];//如果a不是b的根节点,将a设为b的根节点
sum+=road[i].w;
}
}
}
//最短路径算法,在有向图中求。
//Dijstra算法,求指定源点到其余各点的最短路径,时间复杂度为O(n*2)
void Dijstra(MGraph *G,int V0)
{
int dist[maxsize],set[maxsize],path[maxsize];
int v,min,INF=10000,k;
for(int i=0;i<G->n;++i)
{
dist[i]=G->edge[V0][i];
if(dist[i]<INF)//若源点与i之间有通路
path[i]=V0;
else
path[i]=-1;
set[i]=0;
}//初始化完成
v=V0;
set[v]=1;
path[v]=-1;
for(int i=0;i<G->n-1;++i)
{
min=INF;
for(int j=0;j<G->n-1;++j)
{
if(set[j]==0&&dist[j]<min)
{
min=dist[j];
k=j;
}
}
v=k;
set[v]=1;
for(int j=0;j<G->n-1;++j)//以v为中心结点更新
{
if(set[j]==0&&dist[v]+G->edge[v][j]<dist[j])
{
dist[j]=G->edge[v][j];
path[j]=v;//j的前驱结点设为v
}
}
}
}
//Floyed算法,时间复杂度为O(n*3)
void Floyed(MGraph *G)
{
int A[maxsize][maxsize];
int path[maxsize][maxsize];
for(int i=0;i<G->n;++i)
for(int j=0;G->n;++j)
{
A[i][j]=G->edge[i][j];
path[i][j]=-1;
}
//初始化完成
for(int k=0;k<G->n;++k)
for(int i=0;i<G->n;++i)
for(int j=0;j<G->n;++j)
{
if(A[i][k]+A[k][j]<A[i][j])
{
A[i][j]=A[i][k]+A[k][j];
path[i][j]=k;
}
}
}
//拓扑排序(判别图中是否存在环)
//根据排序特点,要在顶点的结构中添加顶点的入度信息
typedef struct
{
int data;
int cout;//储存顶点的入度信息
ArcNode *firstarc;
}Vertex;
int Topsort(Graph *G,int V0)
{
int stack[maxsize],top=-1,v,n=0;
ArcNode *p;
for(int i=0;i<G->n;++i)
if(G->ver[i].cout==0)
stack[++top]=i;//将入度为0的顶点先入栈
while(top!=-1)
{
v=stack[top--];//v指向出栈顶点
++n;
printf("%d",v);//输出出栈顶点
p=G->ver[v].firstarc;
while(p!=NULL)
{
int q=p->adjvex;
--G->ver[q].cout;//入度减少1
if(q==0)//如果减少入度后,入度为零则入栈
{
stack[++top]=q;
}
p=p->nextarc;
}
}
if(n==G->n)
return 1;
else
return 0;
}
//注:使用深度优先搜索也可以进行拓扑排序,同理也可以检测图中的环
//深度优先搜索的非递归算法
void dfs2(Graph *G,int V0)//使用用户定义的栈来代替系统栈
{
int visit[maxsize]={0};
int stack[maxsize],top=-1;
visit[V0]=1;
int v;ArcNode *p;
if(V0!=NULL)
{
stack[++top]=V0;//V0不为空时根节点入栈
//关键部分
while(top!=-1)
{
v=stack[top];//取栈顶顶点
p=G->ver[v].firstarc;
while(p!=NULL&&visit[p->adjvex]==1)//若邻接顶点不为空同时已经访问过
p=p->nextarc;//另p指向另一条边
if(p==NULL)//若相邻边为空时
--top;//退栈
else//若顶点有效且未访问
{
visit[p->adjvex]=1;//置已访问标志
stack[++top]=p->adjvex;//顶点入栈
}
}
}
}