数据结构C语言版(李云清)实验8 图

该博客详细介绍了使用C语言实现图的算法,包括邻接表存储结构的无向图顶点度计算,广度优先遍历,深度优先遍历,Prim求解最小生成树,Dijkstra单源最短路径算法以及拓扑排序算法。内容深入浅出,适合数据结构学习者参考。

实验8 图


1、编写程序输出以邻接表为存储结构的无向图的各顶点的度。

/**********************************/
/*文件名称:lab8_01.c                 */
/**********************************/
#include "ljb.h"
/* 输出以邻接表为存储结构的无向图g的各顶点的度 */
void degree(LinkedGraph g)
{
    EdgeNode *p;
    int count;
    int i;
    for (i=0;i<g.n;i++)
    {
        count=0;
        p=g.adjlist[i].FirstEdge;
        while (p)
        {
            count++;
            p=p->next;
        }
        printf("D(%d)=%d\n",i,count);

    }

}
int main()
{ LinkedGraph g;
  creat(&g,"g11.txt",0);  	/*已知g11.txt中存储了图的信息*/
  printf("\n The graph is:\n");
  print(g);
  degree(g);
  return 0;
}

2、图采用邻接表存储结构,编程对图进行广度优先遍历。

/**********************************/
/*文件名称:lab8_02.c                 */
/**********************************/
#include "ljb.h"
int visited[M];  				/*全局标志向量*/
/*请将本函数补充完整,并进行测试*/
void bfs(LinkedGraph g, int i)
{ /*从顶点i出发广度优先变量图g的连通分量*/
    int queue[M],front,rear,v;
    EdgeNode *p;
    front=rear=0;
    queue[rear++]=i;
    visited[i]=1;
    while (front<rear)
    {
        v=queue[front++];
        printf("%c  ", g.adjlist[v].vertex);
        p=g.adjlist[v].FirstEdge;
        while (p)
        {
            if  (visited[p->adjvex]==0)
                   {
                       queue[rear++]=p->adjvex;
                       visited[p->adjvex]=1;
                   }
            p=p->next;
        }

    }

}


/*函数功能:广度优先遍历图g
  函数参数:邻接表g
*/
int BfsTraverse(LinkedGraph g)
{  int i,count=0;
   for (i=0;i<g.n;i++)
       visited[i]=0;     /*初始化标志数组*/

   for (i=0;i<g.n;i++)
       if (!visited[i])  /*vi未访问过*/
       {printf("\n");
        count++;            /*连通分量个数加1*/
        bfs(g,i);
       }
   return count;
 }

int main()
{ 	  LinkedGraph g;
      int count;
      creat(&g,"g11.txt",0);  		/*创建图的邻接表*/
      printf("\n The graph is:\n");
      print(g);
      printf("广度优先遍历序列为:\n");
      count=BfsTraverse(g);     	/*从顶点0出发广度优先遍历图g*/
      printf("\n该图共有%d个连通分量。\n",count);
      return 0;
}

3、图采用邻接表存储结构,编程对图进行深度优先遍历。

#include "ljb.h"
int visited[M];
/*请将本函数补充完整,并进行测试*/

void dfs(LinkedGraph g,int i)
{   /*从顶点i开始深度优先遍历图的连通分量*/
    EdgeNode *p;
  	printf("visit vertex: %c \n",g.adjlist[i].vertex);/*访问顶点i*/
  	visited[i]=1;
  	p=g.adjlist[i].FirstEdge;
  	while (p)                 /*从p的邻接点出发进行深度优先搜索*/
    {
            if (visited[p->adjvex]==0)
                dfs(g,p->adjvex);
            p=p->next;
    }
}
/*函数功能:深度优先遍历图
  函数参数:图的邻接表g
*/
void DfsTraverse(LinkedGraph g)
{  int i;
   for (i=0;i<g.n;i++)
       visited[i]=0;     /*初始化标志数组*/
   for (i=0;i<g.n;i++)
       if (!visited[i])  /*vi未访问过*/
            dfs(g,i);
 }

int main()
{ LinkedGraph g;
  creat(&g,"g11.txt",0);  			/*创建图的邻接表*/
  printf("\n The graph is:\n");
  print(g);
  printf("深度优先遍历序列为:\n");
  DfsTraverse(g);    				/*从顶点0开始深度优先遍历图无向图g*/
}

4、 Prim求解最小生成树算法

/*********************************************/
/*           Prim求解最小生成树算法          */
/*********************************************/
#include "ljjz.h"

typedef struct edgedata  /*用于保存最小生成树的边类型定义*/
       { int beg,en;     /*beg,en是边顶点序号*/
         int length;     /*边长*/
       }edge;

/*函数功能:prim算法构造最小生成树
函数参数:图的邻接矩阵g;边向量edge
*/
void prim(Mgraph g, edge tree[M-1])
{  edge x;
   int d,min,j,k,s,v;

   /* 建立初始入选点,并初始化生成树边集tree*/
  for (v=1;v<=g.n-1;v++)
  {
      tree[v-1].beg=0;
      tree[v-1].en=v;
      tree[v-1].length=g.edges[0][v];
  }
  /*依次求当前(第k条)最小两栖边,并加入TE*/
  for (k=0;k<=g.n-3;k++)
  {
      min=tree[k].length;
      s=k;
      for (j=k+1;j<=g.n-2;j++)
            if (tree[j].length<min)
            {
                    min=tree[j].length;
                    s=j;
            }
        v=tree[s].en;
        x=tree[s];
        tree[s]=tree[k];
        /*由于新顶点v的加入,修改两栖边的基本信息*/
        for (j=k+1;j<=g.n-2;j++)
        {
            d=g.edges[v][tree[j].en];
            if (d<tree[j].length)
            {
                tree[j].length=d;
                tree[j].beg=v;
            }
        }
  }
   /*输出最小生成树*/
    printf("\n最小生成树是:\n");/*输出最小生成树*/
    for (j=0;j<=g.n-2;j++)
        printf("\n%c---%c  %d\n",g.vexs[tree[j].beg],g.vexs[tree[j].en],tree[j].length);
    printf("\n最小生成树的根是: %c\n", g.vexs[0]);
 }

int  main()
  {
   Mgraph g;
   edge  tree[M-1];  /*用于存放最小生成树的M-1条边*/
   creat(&g,"g.txt",0);  /*创建无向图的邻接矩阵*/
   print(g);
   prim(g,tree);        /*求解图的最小生成树*/

   return 0;

  }


5、Dijkstra单源最短路径算法

/***************************************************/
/*          Dijkstra单源最短路径算法               */
/***************************************************/
#include "ljjz.h"   /*引入邻接矩阵创建程序*/
typedef enum{FALSE,TRUE} boolean;/*false为0,true为1*/
typedef int dist[M];  /* 距离向量类型*/
typedef int path[M];  /* 路径类型*/

/*函数功能:Dijkstra算法求解单源最短路径
函数参数:图的邻接矩阵g;源点v0;路径向量p;距离向量d
*/
void dijkstra(Mgraph g,int v0,path p,dist d)
 { boolean final[M]; /*表示当前元素是否已求出最短路径*/
   int i,k,j,v,min,x;

   /*  第1步  初始化集合S与距离向量d */
    for (v=0;v<g.n;v++)
    {
        final[v]=FALSE;
        d[v]=g.edges[v0][v];
        if (d[v]<FINITY &&d[v]!=0)
                p[v]=v0; else p[v]=-1;
    }
    final[v0]=TRUE;
    d[v0]=0;
   /* 第2步  依次找出n-1个结点加入S中   */
    for (i=1;i<g.n;i++)
    {
        min=FINITY;
        for (k=0;k<g.n;k++)
            if (!final[k] && d[k]<min)
            {
                v=k;
                min=d[k];
            }
            if (min==FINITY)     return ;
            final[v]=TRUE;
    /*第3步 修改S与V-S中各结点的距离*/
    for (k=0;k<g.n;++k)
            if (!final[k] && (min+g.edges[v][k]<d[k]))
            {
                d[k]=min+g.edges[v][k];
                p[k]=v;
            }
    }
}
/*函数功能:输出有向图的最短路径
函数参数:邻接矩阵g;路径向量p;距离向量d
*/
void print_gpd(Mgraph g,path p,dist d)
 {
   int st[M],i,pre,top=-1;
   for (i=0;i<g.n;i++)
    { printf("\nDistancd: %7d , path:" ,d[i]);
      st[++top]=i;
      pre=p[i];
      while (pre!=-1)   /*从第i个顶点开始向前搜索最短路径上的顶点*/
        { st[++top]=pre;
          pre=p[pre];
         }
      while (top>0)
     printf("%2d",st[top--]);
    }
 }
/*---------- 主程序 ------------*/
int main()
 { Mgraph g;   /* 有向图 */
   path p;     /* 路径向量 */
   dist d;     /* 最短路径向量 */
   int v0;
   creat(&g,"g21.txt",1); /*假设图8.21所示的有向网G21的输入文件为g21.txt */
   print(g);        /*输出图的邻接矩阵*/
   printf("\n");
   printf("请输入源点编号:");
   scanf("%d",&v0);       /*输入源点*/
   dijkstra(g,v0,p,d);   /*求v0到其他各点的最短距离*/
   /*输出V0到其它各点的路径信息及距离*/
   print_gpd(g,p,d);

    return 0;
  }

6、 拓扑排序算法

/***************************************/
/*             拓扑排序算法            */
/***************************************/
#include<stdlib.h>
#include<stdio.h>
#define M 20
typedef char vertextype;
typedef struct node{      /*边结点类型定义*/
      int adjvex;
      struct node *next;
  }edgenode;
typedef struct de         /*带顶点入度的头结点定义*/
  {
   edgenode* FirstEdge;
   vertextype vertex;
   int id;                /*顶点的入度域*/
  }vertexnode;

typedef struct{           /*AOV网络的邻接表结构*/
      vertexnode adjlist[M];
      int n,e;
      }AovGraph;

void  creat(AovGraph *g,char *filename)       /*建立AOV网络的存储结构*/
 { int i,j,k;
   edgenode  *s;
   FILE *fp;
   fp=fopen(filename,"r");
   if (fp)
   {
   fscanf(fp,"%d%d",&g->n,&g->e);  /*输入图中的顶点数与边数*/

   for(i=0;i<g->n;i++)                        /*输入顶点值*/
      {fscanf(fp,"%1s",&g->adjlist[i].vertex);
       g->adjlist[i].FirstEdge=NULL;
       g->adjlist[i].id=0;       /*入度初始化为0*/
      }
   for(k=0;k<g->e;k++)
        { fscanf(fp,"%d%d",&i,&j);
         s=(edgenode*)malloc(sizeof(edgenode));
         s->adjvex=j;
         g->adjlist[j].id++;    /*顶点j的入度加1*/
         s->next=g->adjlist[i].FirstEdge;
         g->adjlist[i].FirstEdge=s;
        }
   }
 }

void print(AovGraph g)
{  edgenode *p;
   int i;
  for (i=0;i<g.n;i++)
   { printf("%c %d   ", g.adjlist[i].vertex,g.adjlist[i].id);
     p=g.adjlist[i].FirstEdge;
     while (p)
      { printf("%d-->",p->adjvex);
        p=p->next;
      }
     printf("\n");
   }
}
/*函数功能:拓扑排序
函数参数:AOV网邻接表存储结构变量g
函数返回值:拓扑排序输出的顶点个数
*/
int TopSort(AovGraph g)
 {int k=0,i,j,v, flag[M];
   int queue[M];  /*队列*/
   int h=0,t=0;
   edgenode* p;
   for (i=0;i<g.n;i++)  flag[i]=0;  /*访问标记初始化*/
    /*先将所有入度为0的结点进队*/
    /*将程序补充完整*/

  for (i=0;i<g.n;i++)
        if (g.adjlist[i].id==0)
        {
            queue[t++]=i;
            flag[i]=1;
        }
   while (h<t)
   {
       v=queue[h++];
       printf("%c",g.adjlist[v].vertex);
       k++;
       p=g.adjlist[v].FirstEdge;
       while (p)
       {
           j=p->adjvex;
           g.adjlist[j].id--;
           if (g.adjlist[j].id==0 && flag[j]==0)
           {  queue[t++]=j;
               flag[j]=1;
           }
           p=p->next;
       }

   }
    return k;  //返回输出的顶点个数
 }
int main()
{ int k=0;
  AovGraph g;
  creat(&g,"aov.txt");    /*假设图8.25所示的AOV网输入文件为aov.txt*/
  printf("\n图8.27所示AOV网的邻接表是:\n");
  print(g);
  k=TopSort(g);
  if(k<g.n) printf("\n该图存在环!\n");
  return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值