图的基本结构及相关算法

//图的邻接矩阵结构
# 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;//顶点入栈
    }
   }
  }
 }

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值