[数据结构]图相关算法


1.7 图

1.7.1 图的邻接矩阵存储表示

#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 5 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 20 /* 相关信息字符串的最大长度+1 */
typedef int VRType;
typedef char InfoType;
typedef char VertexType[MAX_NAME];
#define INFINITY INT_MAX /* 用整型最大值代替∞ */
#define MAX_VERTEX_NUM 20 /* 最大顶点个数 */
typedef enum{DG,DN,AG,AN}GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct
{
  VRType adj; /* 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; */
       /* 对带权图,c则为权值类型 */
  InfoType *info; /* 该弧相关信息的指针(可无) */
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct
{
  VertexType vexs[MAX_VERTEX_NUM]; /* 顶点向量 */
  AdjMatrix arcs; /* 邻接矩阵 */
  int vexnum,arcnum; /* 图的当前顶点数和弧数 */
  GraphKind kind; /* 图的种类标志 */
}MGraph;
/* 图的数组(邻接矩阵)存储(存储结构由定义)的基本操作*/
int LocateVex(MGraph G,VertexType u)
{ /* 初始条件:图G存在,u和G中顶点有相同特征 */
  /* 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
  int i;
  for(i=0;i<G.vexnum;++i)
    if(strcmp(u,G.vexs[i])==0)
      return i;
  return -1;
}

Status CreateFAG(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,由文件构造没有相关信息的无向图G */
  int i,j,k;
  char filename[13];
  VertexType va,vb;
  FILE *graphlist;
  printf("请输入数据文件名(f7-1.dat):");
  scanf("%s",filename);
  graphlist=fopen(filename,"r");
  fscanf(graphlist,"%d",&(*G).vexnum);
  fscanf(graphlist,"%d",&(*G).arcnum);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    fscanf(graphlist,"%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=0; /* 图 */
      (*G).arcs[i][j].info=NULL; /* 没有相关信息 */
    }
  for(k=0;k<(*G).arcnum;++k)
  {
    fscanf(graphlist,"%s%s",va,vb);
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=(*G).arcs[j][i].adj=1; /* 无向图 */
  }
  fclose(graphlist);
  (*G).kind=AG;
  return OK;
}

Status CreateDG(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造有向图G */
  int i,j,k,l,IncInfo;
  char s[MAX_INFO],*info;
  VertexType va,vb;
  printf("请输入有向图G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    scanf("%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=0; /* 图 */
      (*G).arcs[i][j].info=NULL;
    }
  printf("请输入%d条弧的弧尾 弧头(以空格作为间隔): \n",(*G).arcnum);
  for(k=0;k<(*G).arcnum;++k)
  {
    scanf("%s%s%*c",va,vb);  /* %*c吃掉回车符 */
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=1; /* 有向图 */
    if(IncInfo)
    {
      printf("请输入该弧的相关信息(<%d个字符): ",MAX_INFO);
      gets(s);
      l=strlen(s);
      if(l)
      {
        info=(char*)malloc((l+1)*sizeof(char));
        strcpy(info,s);
        (*G).arcs[i][j].info=info; /* 有向 */
      }
    }
  }
  (*G).kind=DG;
  return OK;
}

Status CreateDN(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造有向网G */
  int i,j,k,w,IncInfo;
  char s[MAX_INFO],*info;
  VertexType va,vb;
  printf("请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    scanf("%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=INFINITY; /* 网 */
      (*G).arcs[i][j].info=NULL;
    }
  printf("请输入%d条弧的弧尾 弧头 权值(以空格作为间隔): \n",(*G).arcnum);
  for(k=0;k<(*G).arcnum;++k)
  {
    scanf("%s%s%d%*c",va,vb,&w);  /* %*c吃掉回车符 */
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=w; /* 有向网 */
    if(IncInfo)
    {
      printf("请输入该弧的相关信息(<%d个字符): ",MAX_INFO);
      gets(s);
      w=strlen(s);
      if(w)
      {
        info=(char*)malloc((w+1)*sizeof(char));
        strcpy(info,s);
        (*G).arcs[i][j].info=info; /* 有向 */
      }
    }
  }
  (*G).kind=DN;
  return OK;
}

Status CreateAG(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造无向图G */
  int i,j,k,l,IncInfo;
  char s[MAX_INFO],*info;
  VertexType va,vb;
  printf("请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    scanf("%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=0; /* 图 */
      (*G).arcs[i][j].info=NULL;
    }
  printf("请输入%d条边的顶点1 顶点2(以空格作为间隔): \n",(*G).arcnum);
  for(k=0;k<(*G).arcnum;++k)
  {
    scanf("%s%s%*c",va,vb); /* %*c吃掉回车符 */
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=(*G).arcs[j][i].adj=1; /* 无向图 */
    if(IncInfo)
    {
      printf("请输入该边的相关信息(<%d个字符): ",MAX_INFO);
      gets(s);
      l=strlen(s);
      if(l)
      {
        info=(char*)malloc((l+1)*sizeof(char));
        strcpy(info,s);
        (*G).arcs[i][j].info=(*G).arcs[j][i].info=info; /* 无向 */
      }
    }
  }
  (*G).kind=AG;
  return OK;
}

Status CreateAN(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造无向网G。*/
  int i,j,k,w,IncInfo;
  char s[MAX_INFO],*info;
  VertexType va,vb;
  printf("请输入无向网G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    scanf("%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=INFINITY; /* 网 */
      (*G).arcs[i][j].info=NULL;
    }
  printf("请输入%d条边的顶点1 顶点2 权值(以空格作为间隔): \n",(*G).arcnum);
  for(k=0;k<(*G).arcnum;++k)
  {
    scanf("%s%s%d%*c",va,vb,&w); /* %*c吃掉回车符 */
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=(*G).arcs[j][i].adj=w; /* 无向 */
    if(IncInfo)
    {
      printf("请输入该边的相关信息(<%d个字符): ",MAX_INFO);
      gets(s);
      w=strlen(s);
      if(w)
      {
        info=(char*)malloc((w+1)*sizeof(char));
        strcpy(info,s);
        (*G).arcs[i][j].info=(*G).arcs[j][i].info=info; /* 无向 */
      }
    }
  }
  (*G).kind=AN;
  return OK;
}

Status CreateGraph(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造图G。*/
  printf("请输入图G的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
  scanf("%d",&(*G).kind);
  switch((*G).kind)
  {
    case DG: return CreateDG(G); /* 构造有向图 */
    case DN: return CreateDN(G); /* 构造有向网 */
    case AG: return CreateAG(G); /* 构造无向图 */
    case AN: return CreateAN(G); /* 构造无向网 */
    default: return ERROR;
  }
}

void DestroyGraph(MGraph *G)
{ /* 初始条件: 图G存在。操作结果: 销毁图G */
  int i,j;
  if((*G).kind<2) /* 有向 */
    for(i=0;i<(*G).vexnum;i++) /* 释放弧的相关信息(如果有的话) */
    {
      for(j=0;j<(*G).vexnum;j++)
        if((*G).arcs[i][j].adj==1&&(*G).kind==0||(*G).arcs[i][j].adj!=INFINITY&&(*G).kind==1) /* 有向图的弧||有向网的弧 */
          if((*G).arcs[i][j].info) /* 有相关信息 */
          {
            free((*G).arcs[i][j].info);
            (*G).arcs[i][j].info=NULL;
          }
    }
  else /* 无向 */
    for(i=0;i<(*G).vexnum;i++) /* 释放边的相关信息(如果有的话) */
      for(j=i+1;j<(*G).vexnum;j++)
        if((*G).arcs[i][j].adj==1&&(*G).kind==2||(*G).arcs[i][j].adj!=INFINITY&&(*G).kind==3) /* 无向图的边||无向网的边 */
          if((*G).arcs[i][j].info) /* 有相关信息 */
          {
            free((*G).arcs[i][j].info);
            (*G).arcs[i][j].info=(*G).arcs[j][i].info=NULL;
          }
  (*G).vexnum=0;
  (*G).arcnum=0;
}

VertexType* GetVex(MGraph G,int v)
{ /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
  if(v>=G.vexnum||v<0)
    exit(ERROR);
  return &G.vexs[v];
}

Status PutVex(MGraph *G,VertexType v,VertexType value)
{ /* 初始条件: 图G存在,v是G中某个顶点。操作结果: 对v赋新值value */
  int k;
  k=LocateVex(*G,v); /* k为顶点v在图G中的序号 */
  if(k<0)
    return ERROR;
  strcpy((*G).vexs[k],value);
  return OK;
}

int FirstAdjVex(MGraph G,VertexType v)
{ /* 初始条件: 图G存在,v是G中某个顶点 */
  /* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
  int i,j=0,k;
  k=LocateVex(G,v); /* k为顶点v在图G中的序号 */
  if(G.kind==DN||G.kind==AN) /* 网 */
    j=INFINITY;
  for(i=0;i<G.vexnum;i++)
    if(G.arcs[k][i].adj!=j)
      return i;
  return -1;
}

int NextAdjVex(MGraph G,VertexType v,VertexType w)
{ /* 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点 */
  /* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号, */
  /*           若w是v的最后一个邻接顶点,则返回-1 */
  int i,j=0,k1,k2;
  k1=LocateVex(G,v); /* k1为顶点v在图G中的序号 */
  k2=LocateVex(G,w); /* k2为顶点w在图G中的序号 */
  if(G.kind==DN||G.kind==AN) /* 网 */
    j=INFINITY;
  for(i=k2+1;i<G.vexnum;i++)
    if(G.arcs[k1][i].adj!=j)
      return i;
  return -1;
}

void InsertVex(MGraph *G,VertexType v)
{ /* 初始条件: 图G存在,v和图G中顶点有相同特征 */
  /* 操作结果: 在图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做) */
  int i;
  strcpy((*G).vexs[(*G).vexnum],v); /* 构造新顶点向量 */
  for(i=0;i<=(*G).vexnum;i++)
  {
    if((*G).kind%2) /* 网 */
    {
      (*G).arcs[(*G).vexnum][i].adj=INFINITY; /* 初始化该行邻接矩阵的值(无边或弧) */
      (*G).arcs[i][(*G).vexnum].adj=INFINITY; /* 初始化该列邻接矩阵的值(无边或弧) */
    }
    else /* 图 */
    {
      (*G).arcs[(*G).vexnum][i].adj=0; /* 初始化该行邻接矩阵的值(无边或弧) */
      (*G).arcs[i][(*G).vexnum].adj=0; /* 初始化该列邻接矩阵的值(无边或弧) */
    }
    (*G).arcs[(*G).vexnum][i].info=NULL; /* 初始化相关信息指针 */
    (*G).arcs[i][(*G).vexnum].info=NULL;
  }
  (*G).vexnum+=1; /* 图G的顶点数加1 */
}

Status DeleteVex(MGraph *G,VertexType v)
{ /* 初始条件: 图G存在,v是G中某个顶点。操作结果: 删除G中顶点v及其相关的弧 */
  int i,j,k;
  VRType m=0;
  k=LocateVex(*G,v); /* k为待删除顶点v的序号 */
  if(k<0) /* v不是图G的顶点 */
    return ERROR;
  if((*G).kind==DN||(*G).kind==AN) /* 网 */
    m=INFINITY;
  for(j=0;j<(*G).vexnum;j++)
    if((*G).arcs[j][k].adj!=m) /* 有入弧或边 */
    {
      if((*G).arcs[j][k].info) /* 有相关信息 */
        free((*G).arcs[j][k].info); /* 释放相关信息 */
      (*G).arcnum--; /* 修改弧数 */
    }
  if((*G).kind==DG||(*G).kind==DN) /* 有向 */
    for(j=0;j<(*G).vexnum;j++)
      if((*G).arcs[k][j].adj!=m) /* 有出弧 */
      {
        if((*G).arcs[k][j].info) /* 有相关信息 */
          free((*G).arcs[k][j].info); /* 释放相关信息 */
        (*G).arcnum--; /* 修改弧数 */
      }
  for(j=k+1;j<(*G).vexnum;j++) /* 序号k后面的顶点向量依次前移 */
    strcpy((*G).vexs[j-1],(*G).vexs[j]);
  for(i=0;i<(*G).vexnum;i++)
    for(j=k+1;j<(*G).vexnum;j++)
      (*G).arcs[i][j-1]=(*G).arcs[i][j]; /* 移动待删除顶点之后的矩阵元素 */
  for(i=0;i<(*G).vexnum;i++)
    for(j=k+1;j<(*G).vexnum;j++)
      (*G).arcs[j-1][i]=(*G).arcs[j][i]; /* 移动待删除顶点之下的矩阵元素 */
  (*G).vexnum--; /* 更新图的顶点数 */
  return OK;
}

Status InsertArc(MGraph *G,VertexType v,VertexType w)
{ /* 初始条件: 图G存在,v和W是G中两个顶点 */
  /* 操作结果: 在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v> */
  int i,l,v1,w1;
  char *info,s[MAX_INFO];
  v1=LocateVex(*G,v); /* 尾 */
  w1=LocateVex(*G,w); /* 头 */
  if(v1<0||w1<0)
    return ERROR;
  (*G).arcnum++; /* 弧或边数加1 */
  if((*G).kind%2) /* 网 */
  {
    printf("请输入此弧或边的权值: ");
    scanf("%d",&(*G).arcs[v1][w1].adj);
  }
  else /* 图 */
    (*G).arcs[v1][w1].adj=1;
  printf("是否有该弧或边的相关信息(0:无 1:有): ");
  scanf("%d%*c",&i);
  if(i)
  {
    printf("请输入该弧或边的相关信息(<%d个字符):",MAX_INFO);
    gets(s);
    l=strlen(s);
    if(l)
    {
      info=(char*)malloc((l+1)*sizeof(char));
      strcpy(info,s);
      (*G).arcs[v1][w1].info=info;
    }
  }
  if((*G).kind>1) /* 无向 */
  {
    (*G).arcs[w1][v1].adj=(*G).arcs[v1][w1].adj;
    (*G).arcs[w1][v1].info=(*G).arcs[v1][w1].info; /* 指向同一个相关信息 */
  }
  return OK;
}

Status DeleteArc(MGraph *G,VertexType v,VertexType w)
{ /* 初始条件: 图G存在,v和w是G中两个顶点 */
  /* 操作结果: 在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v> */
  int v1,w1;
  v1=LocateVex(*G,v); /* 尾 */
  w1=LocateVex(*G,w); /* 头 */
  if(v1<0||w1<0) /* v1、w1的值不合法 */
    return ERROR;
  if((*G).kind%2==0) /* 图 */
    (*G).arcs[v1][w1].adj=0;
  else /* 网 */
    (*G).arcs[v1][w1].adj=INFINITY;
  if((*G).arcs[v1][w1].info) /* 有其它信息 */
  {
    free((*G).arcs[v1][w1].info);
    (*G).arcs[v1][w1].info=NULL;
  }
  if((*G).kind>=2) /* 无向,删除对称弧<w,v> */
  {
    (*G).arcs[w1][v1].adj=(*G).arcs[v1][w1].adj;
    (*G).arcs[w1][v1].info=NULL;
  }
  (*G).arcnum--;
  return OK;
}

Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
Status(*VisitFunc)(VertexType); /* 函数变量 */
void DFS(MGraph G,int v)
{ /* 从第v个顶点出发递归地深度优先遍历图G。*/
  VertexType w1,v1;
  int w;
  visited[v]=TRUE; /* 设置访问标志为TRUE(已访问) */
  VisitFunc(G.vexs[v]); /* 访问第v个顶点 */
  strcpy(v1,*GetVex(G,v));
  for(w=FirstAdjVex(G,v1);w>=0;w=NextAdjVex(G,v1,strcpy(w1,*GetVex(G,w))))
    if(!visited[w])
      DFS(G,w); /* 对v的尚未访问的序号为w的邻接顶点递归调用DFS */
}

void DFSTraverse(MGraph G,Status(*Visit)(VertexType))
{ /* 初始条件: 图G存在,Visit是顶点的应用函数。*/
  /* 操作结果: 从第1个顶点起,深度优先遍历图G,并对每个顶点调用函数Visit */
  /*           一次且仅一次。一旦Visit()失败,则操作失败 */
  int v;
  VisitFunc=Visit; /* 使用全局变量VisitFunc,使DFS不必设函数指针参数 */
  for(v=0;v<G.vexnum;v++)
    visited[v]=FALSE; /* 访问标志数组初始化(未被访问) */
  for(v=0;v<G.vexnum;v++)
    if(!visited[v])
      DFS(G,v); /* 对尚未访问的顶点调用DFS */
  printf("\n");
}

typedef VRType QElemType; /* 队列类型 */
typedef struct QNode
{
  QElemType data;
  struct QNode *next;
}QNode,*QueuePtr;

typedef struct
{
  QueuePtr front,rear; /* 队头、队尾指针 */
}LinkQueue;
Status InitQueue(LinkQueue *Q)
{ /* 构造一个空队列Q */
  (*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));
  if(!(*Q).front)
    exit(OVERFLOW);
  (*Q).front->next=NULL;
  return OK;
}
Status QueueEmpty(LinkQueue Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */
  if(Q.front==Q.rear)
    return TRUE;
  else
    return FALSE;
}

Status EnQueue(LinkQueue *Q,QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
  QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
  if(!p) /* 存储分配失败 */
    exit(OVERFLOW);
  p->data=e;
  p->next=NULL;
  (*Q).rear->next=p;
  (*Q).rear=p;
  return OK;
}

Status DeQueue(LinkQueue *Q,QElemType *e)
{ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
  QueuePtr p;
  if((*Q).front==(*Q).rear)
    return ERROR;
  p=(*Q).front->next;
  *e=p->data;
  (*Q).front->next=p->next;
  if((*Q).rear==p)
    (*Q).rear=(*Q).front;
  free(p);
  return OK;
}
void BFSTraverse(MGraph G,Status(*Visit)(VertexType))
{ /* 初始条件: 图G存在,Visit是顶点的应用函数。*/
  /* 操作结果: 从第1个顶点起,按广度优先非递归遍历图G,并对每个顶点调用函数 */
  /*           Visit一次且仅一次。一旦Visit()失败,则操作失败。 */
  /*           使用辅助队列Q和访问标志数组visited */
  int v,u,w;
  VertexType w1,u1;
  LinkQueue Q;
  for(v=0;v<G.vexnum;v++)
    visited[v]=FALSE; /* 置初值 */
  InitQueue(&Q); /* 置空的辅助队列Q */
  for(v=0;v<G.vexnum;v++)
    if(!visited[v]) /* v尚未访问 */
    {
      visited[v]=TRUE; /* 设置访问标志为TRUE(已访问) */
      Visit(G.vexs[v]);
      EnQueue(&Q,v); /* v入队列 */
      while(!QueueEmpty(Q)) /* 队列不空 */
      {
        DeQueue(&Q,&u); /* 队头元素出队并置为u */
        strcpy(u1,*GetVex(G,u));
        for(w=FirstAdjVex(G,u1);w>=0;w=NextAdjVex(G,u1,strcpy(w1,*GetVex(G,w))))
          if(!visited[w]) /* w为u的尚未访问的邻接顶点的序号 */
          {
            visited[w]=TRUE;
            Visit(G.vexs[w]);
            EnQueue(&Q,w);
          }
      }
    }
  printf("\n");
}

void Display(MGraph G)
{ /* 输出邻接矩阵G */
  int i,j;
  char s[7],s1[3];
  switch(G.kind)
  {
    case DG: strcpy(s,"有向图\0");
             strcpy(s1,"弧\0");
             break;
    case DN: strcpy(s,"有向网\0");
             strcpy(s1,"弧\0");
             break;
    case AG: strcpy(s,"无向图\0");
             strcpy(s1,"边\0");
             break;
    case AN: strcpy(s,"无向网\0");
             strcpy(s1,"边\0");
  }
  printf("%d个顶点%d条%s的%s\n",G.vexnum,G.arcnum,s1,s);
  for(i=0;i<G.vexnum;++i) /* 输出G.vexs */
    printf("G.vexs[%d]=%s\n",i,G.vexs[i]);
  printf("G.arcs.adj:\n"); /* 输出G.arcs.adj */
  for(i=0;i<G.vexnum;i++)
  {
    for(j=0;j<G.vexnum;j++)
      printf("%6d",G.arcs[i][j].adj);
    printf("\n");
  }
  printf("G.arcs.info:\n"); /* 输出G.arcs.info */
  printf("顶点1(弧尾) 顶点2(弧头) 该%s信息:\n",s1);
  if(G.kind<2) /* 有向 */
    for(i=0;i<G.vexnum;i++)
      for(j=0;j<G.vexnum;j++)
      {
        if(G.arcs[i][j].info)
          printf("%5s %11s     %s\n",G.vexs[i],G.vexs[j],G.arcs[i][j].info);
      }
  else /* 无向 */
  {
    for(i=0;i<G.vexnum;i++)
      for(j=i+1;j<G.vexnum;j++)
 if(G.arcs[i][j].info)
   printf("%5s %11s     %s\n",G.vexs[i],G.vexs[j],G.arcs[i][j].info);
  }
}

Status visit(VertexType i)
{
  printf("%s ",i);
  return OK;
}

void main()
{
  int i,j,k,n;
  VertexType v1,v2;
  MGraph g;
  CreateFAG(&g);
  Display(g);
  printf("修改顶点的值,请输入原值 新值: ");
  scanf("%s%s",v1,v2);
  PutVex(&g,v1,v2);
  printf("深度优先搜索的结果:\n");
  DFSTraverse(g,visit);
  printf("广度优先搜索的结果:\n");
  BFSTraverse(g,visit);
  printf("删除一条边或弧,请输入待删除边或弧的弧尾 弧头:");
  scanf("%s%s",v1,v2);
  DeleteArc(&g,v1,v2);
  Display(g);
  DestroyGraph(&g);
  printf("请顺序选择有向图,有向网,无向图,无向网\n");
  for(i=0;i<4;i++) /* 验证4种情况 */
  {
    CreateGraph(&g);
    Display(g);
    printf("插入新顶点,请输入顶点的值: ");
    scanf("%s",v1);
    InsertVex(&g,v1);
    printf("插入与新顶点有关的弧或边,请输入弧或边数: ");
    scanf("%d",&n);
    for(k=0;k<n;k++)
    {
      printf("请输入另一顶点的值: ");
      scanf("%s",v2);
      if(g.kind<=1) /* 有向 */
      {
        printf("对于有向图或网,请输入另一顶点的方向(0:弧头 1:弧尾): ");
        scanf("%d",&j);
        if(j)
          InsertArc(&g,v2,v1);
        else
          InsertArc(&g,v1,v2);
      }
      else /* 无向 */
        InsertArc(&g,v1,v2);
    }
    Display(g);
    printf("删除顶点及相关的弧或边,请输入顶点的值: ");
    scanf("%s",v1);
    DeleteVex(&g,v1);
    Display(g);
    DestroyGraph(&g);
  }
}

运行结果:

 retrun list 

1.7.2 图的邻接表存储表示

#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 3 /* 顶点字符串的最大长度+1 */
typedef int InfoType; /* 存放网的权值 */
typedef char VertexType[MAX_NAME]; /* 字符串类型 */
/*图的邻接表存储表示 */
#define MAX_VERTEX_NUM 20
typedef enum{DG,DN,AG,AN}GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct ArcNode
{
  int adjvex; /* 该弧所指向的顶点的位置 */
  struct ArcNode *nextarc; /* 指向下一条弧的指针 */
  InfoType *info; /* 网的权值指针) */
}ArcNode; /* 表结点 */
typedef struct
{
  VertexType data; /* 顶点信息 */
  ArcNode *firstarc; /* 第一个表结点的地址,指向第一条依附该顶点的弧的指针 */
}VNode,AdjList[MAX_VERTEX_NUM]; /* 头结点 */
typedef struct
{
  AdjList vertices;
  int vexnum,arcnum; /* 图的当前顶点数和弧数 */
  int kind; /* 图的种类标志 */
}ALGraph;
/* 图的邻接表存储的基本操作*/
int LocateVex(ALGraph G,VertexType u)
{ /* 初始条件: 图G存在,u和G中顶点有相同特征 */
  /* 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
  int i;
  for(i=0;i<G.vexnum;++i)
    if(strcmp(u,G.vertices[i].data)==0)
      return i;
  return -1;
}
Status CreateGraph(ALGraph *G)
{ /* 采用邻接表存储结构,构造没有相关信息的图G*/
  int i,j,k;
  int w; /* 权值 */
  VertexType va,vb;
  ArcNode *p;
  printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
  scanf("%d",&(*G).kind);
  printf("请输入图的顶点数,边数: ");
  scanf("%d,%d",&(*G).vexnum,&(*G).arcnum);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
  {
    scanf("%s",(*G).vertices[i].data);
    (*G).vertices[i].firstarc=NULL;
  }
  if((*G).kind==1||(*G).kind==3) /* 网 */
    printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");
  else /* 图 */
    printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");
  for(k=0;k<(*G).arcnum;++k) /* 构造表结点链表 */
  {
    if((*G).kind==1||(*G).kind==3) /* 网 */
      scanf("%d%s%s",&w,va,vb);
    else /* 图 */
      scanf("%s%s",va,vb);
    i=LocateVex(*G,va); /* 弧尾 */
    j=LocateVex(*G,vb); /* 弧头 */
    p=(ArcNode*)malloc(sizeof(ArcNode));
    p->adjvex=j;
    if((*G).kind==1||(*G).kind==3) /* 网 */
    {
      p->info=(int *)malloc(sizeof(int));
      *(p->info)=w;
    }
    else
      p->info=NULL; /* 图 */
    p->nextarc=(*G).vertices[i].firstarc; /* 插在表头 */
    (*G).vertices[i].firstarc=p;
    if((*G).kind>=2) /* 无向图或网,产生第二个表结点 */
    {
      p=(ArcNode*)malloc(sizeof(ArcNode));
      p->adjvex=i;
      if((*G).kind==3) /* 无向网 */
      {
        p->info=(int*)malloc(sizeof(int));
        *(p->info)=w;
      }
      else
        p->info=NULL; /* 无向图 */
      p->nextarc=(*G).vertices[j].firstarc; /* 插在表头 */
      (*G).vertices[j].firstarc=p;
    }
  }
  return OK;
}
void DestroyGraph(ALGraph *G)
{ /* 初始条件: 图G存在。操作结果: 销毁图G */
  int i;
  ArcNode *p,*q;
  (*G).vexnum=0;
  (*G).arcnum=0;
  for(i=0;i<(*G).vexnum;++i)
  {
    p=(*G).vertices[i].firstarc;
    while(p)
    {
      q=p->nextarc;
      if((*G).kind%2) /* 网 */
        free(p->info);
      free(p);
      p=q;
    }
  }
}
VertexType* GetVex(ALGraph G,int v)
{ /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
  if(v>=G.vexnum||v<0)
    exit(ERROR);
  return &G.vertices[v].data;
}
Status PutVex(ALGraph *G,VertexType v,VertexType value)
{ /* 初始条件: 图G存在,v是G中某个顶点 */
  /* 操作结果: 对v赋新值value */
  int i;
  i=LocateVex(*G,v);
  if(i>-1) /* v是G的顶点 */
  {
    strcpy((*G).vertices[i].data,value);
    return OK;
  }
  return ERROR;
}
int FirstAdjVex(ALGraph G,VertexType v)
{ /* 初始条件: 图G存在,v是G中某个顶点 */
  /* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
  ArcNode *p;
  int v1;
  v1=LocateVex(G,v); /* v1为顶点v在图G中的序号 */
  p=G.vertices[v1].firstarc;
  if(p)
    return p->adjvex;
  else
    return -1;
}
int NextAdjVex(ALGraph G,VertexType v,VertexType w)
{ /* 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点 */
  /* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。 */
  /*           若w是v的最后一个邻接点,则返回-1 */
  ArcNode *p;
  int v1,w1;
  v1=LocateVex(G,v); /* v1为顶点v在图G中的序号 */
  w1=LocateVex(G,w); /* w1为顶点w在图G中的序号 */
  p=G.vertices[v1].firstarc;
  while(p&&p->adjvex!=w1) /* 指针p不空且所指表结点不是w */
    p=p->nextarc;
  if(!p||!p->nextarc) /* 没找到w或w是最后一个邻接点 */
    return -1;
  else /* p->adjvex==w */
    return p->nextarc->adjvex; /* 返回v的(相对于w的)下一个邻接顶点的序号 */
}
void InsertVex(ALGraph *G,VertexType v)
{ /* 初始条件: 图G存在,v和图中顶点有相同特征 */
  /* 操作结果: 在图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做) */
  strcpy((*G).vertices[(*G).vexnum].data,v); /* 构造新顶点向量 */
  (*G).vertices[(*G).vexnum].firstarc=NULL;
  (*G).vexnum++; /* 图G的顶点数加1 */
}
Status DeleteVex(ALGraph *G,VertexType v)
{ /* 初始条件: 图G存在,v是G中某个顶点 */
  /* 操作结果: 删除G中顶点v及其相关的弧 */
  int i,j;
  ArcNode *p,*q;
  j=LocateVex(*G,v); /* j是顶点v的序号 */
  if(j<0) /* v不是图G的顶点 */
    return ERROR;
  p=(*G).vertices[j].firstarc; /* 删除以v为出度的弧或边 */
  while(p)
  {
    q=p;
    p=p->nextarc;
    if((*G).kind%2) /* 网 */
      free(q->info);
    free(q);
    (*G).arcnum--; /* 弧或边数减1 */
  }
  (*G).vexnum--; /* 顶点数减1 */
  for(i=j;i<(*G).vexnum;i++) /* 顶点v后面的顶点前移 */
    (*G).vertices[i]=(*G).vertices[i+1];
  for(i=0;i<(*G).vexnum;i++) /* 删除以v为入度的弧或边且必要时修改表结点的顶点位置值 */
  {
    p=(*G).vertices[i].firstarc; /* 指向第1条弧或边 */
    while(p) /* 有弧 */
    {
      if(p->adjvex==j)
      {
        if(p==(*G).vertices[i].firstarc) /* 待删结点是第1个结点 */
        {
          (*G).vertices[i].firstarc=p->nextarc;
          if((*G).kind%2) /* 网 */
            free(p->info);
          free(p);
          p=(*G).vertices[i].firstarc;
          if((*G).kind<2) /* 有向 */
            (*G).arcnum--; /* 弧或边数减1 */
        }
        else
        {
          q->nextarc=p->nextarc;
          if((*G).kind%2) /* 网 */
            free(p->info);
          free(p);
          p=q->nextarc;
          if((*G).kind<2) /* 有向 */
            (*G).arcnum--; /* 弧或边数减1 */
        }
      }
      else
      {
        if(p->adjvex>j)
          p->adjvex--; /* 修改表结点的顶点位置值(序号) */
        q=p;
        p=p->nextarc;
      }
    }
  }
  return OK;
}
Status InsertArc(ALGraph *G,VertexType v,VertexType w)
{ /* 初始条件: 图G存在,v和w是G中两个顶点 */
  /* 操作结果: 在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v> */
  ArcNode *p;
  int w1,i,j;
  i=LocateVex(*G,v); /* 弧尾或边的序号 */
  j=LocateVex(*G,w); /* 弧头或边的序号 */
  if(i<0||j<0)
    return ERROR;
  (*G).arcnum++; /* 图G的弧或边的数目加1 */
  if((*G).kind%2) /* 网 */
  {
    printf("请输入弧(边)%s→%s的权值: ",v,w);
    scanf("%d",&w1);
  }
  p=(ArcNode*)malloc(sizeof(ArcNode));
  p->adjvex=j;
  if((*G).kind%2) /* 网 */
  {
    p->info=(int*)malloc(sizeof(int));
    *(p->info)=w1;
  }
  else
    p->info=NULL;
  p->nextarc=(*G).vertices[i].firstarc; /* 插在表头 */
  (*G).vertices[i].firstarc=p;
  if((*G).kind>=2) /* 无向,生成另一个表结点 */
  {
    p=(ArcNode*)malloc(sizeof(ArcNode));
    p->adjvex=i;
    if((*G).kind==3) /* 无向网 */
    {
      p->info=(int*)malloc(sizeof(int));
      *(p->info)=w1;
    }
    else
      p->info=NULL;
    p->nextarc=(*G).vertices[j].firstarc; /* 插在表头 */
    (*G).vertices[j].firstarc=p;
  }
  return OK;
}
Status DeleteArc(ALGraph *G,VertexType v,VertexType w)
{ /* 初始条件: 图G存在,v和w是G中两个顶点 */
  /* 操作结果: 在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v> */
  ArcNode *p,*q;
  int i,j;
  i=LocateVex(*G,v); /* i是顶点v(弧尾)的序号 */
  j=LocateVex(*G,w); /* j是顶点w(弧头)的序号 */
  if(i<0||j<0||i==j)
    return ERROR;
  p=(*G).vertices[i].firstarc; /* p指向顶点v的第一条出弧 */
  while(p&&p->adjvex!=j) /* p不空且所指之弧不是待删除弧<v,w> */
  { /* p指向下一条弧 */
    q=p;
    p=p->nextarc;
  }
  if(p&&p->adjvex==j) /* 找到弧<v,w> */
  {
    if(p==(*G).vertices[i].firstarc) /* p所指是第1条弧 */
      (*G).vertices[i].firstarc=p->nextarc; /* 指向下一条弧 */
    else
      q->nextarc=p->nextarc; /* 指向下一条弧 */
    if((*G).kind%2) /* 网 */
      free(p->info);
    free(p); /* 释放此结点 */
    (*G).arcnum--; /* 弧或边数减1 */
  }
  if((*G).kind>=2) /* 无向,删除对称弧<w,v> */
  {
    p=(*G).vertices[j].firstarc; /* p指隙サ鉾的第一条出弧 */
    while(p&&p->adjvex!=i) /* p不空且所指之弧不是待删除弧<w,v> */
    { /* p指向下一条弧 */
      q=p;
      p=p->nextarc;
    }
    if(p&&p->adjvex==i) /* 找到弧<w,v> */
    {
      if(p==(*G).vertices[j].firstarc) /* p所指是第1条弧 */
        (*G).vertices[j].firstarc=p->nextarc; /* 指向下一条弧 */
      else
        q->nextarc=p->nextarc; /* 指向下一条弧 */
      if((*G).kind==3) /* 无向网 */
        free(p->info);
      free(p); /* 释放此结点 */
    }
  }
  return OK;
}
Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
void(*VisitFunc)(char* v); /* 函数变量(全局量) */
void DFS(ALGraph G,int v)
{ /* 从第v个顶点出发递归地深度优先遍历图G。*/
  int w;
  VertexType v1,w1;
  strcpy(v1,*GetVex(G,v));
  visited[v]=TRUE; /* 设置访问标志为TRUE(已访问) */
  VisitFunc(G.vertices[v].data); /* 访问第v个顶点 */
  for(w=FirstAdjVex(G,v1);w>=0;w=NextAdjVex(G,v1,strcpy(w1,*GetVex(G,w))))
    if(!visited[w])
      DFS(G,w); /* 对v的尚未访问的邻接点w递归调用DFS */
}
void DFSTraverse(ALGraph G,void(*Visit)(char*))
{ /* 对图G作深度优先遍历。*/
  int v;
  VisitFunc=Visit; /* 使用全局变量VisitFunc,使DFS不必设函数指针参数 */
  for(v=0;v<G.vexnum;v++)
    visited[v]=FALSE; /* 访问标志数组初始化 */
  for(v=0;v<G.vexnum;v++)
    if(!visited[v])
      DFS(G,v); /* 对尚未访问的顶点调用DFS */
  printf("\n");
}
typedef int QElemType; /* 队列类型 */
typedef struct QNode
{
  QElemType data;
  struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
  QueuePtr front,rear; /* 队头、队尾指针 */
}LinkQueue;
Status InitQueue(LinkQueue *Q)
{ /* 构造一个空队列Q */
  (*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));
  if(!(*Q).front)
    exit(OVERFLOW);
  (*Q).front->next=NULL;
  return OK;
}
Status QueueEmpty(LinkQueue Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */
  if(Q.front==Q.rear)
    return TRUE;
  else
    return FALSE;
}
Status EnQueue(LinkQueue *Q,QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
  QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
  if(!p) /* 存储分配失败 */
    exit(OVERFLOW);
  p->data=e;
  p->next=NULL;
  (*Q).rear->next=p;
  (*Q).rear=p;
  return OK;
}
Status DeQueue(LinkQueue *Q,QElemType *e)
{ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
  QueuePtr p;
  if((*Q).front==(*Q).rear)
    return ERROR;
  p=(*Q).front->next;
  *e=p->data;
  (*Q).front->next=p->next;
  if((*Q).rear==p)
    (*Q).rear=(*Q).front;
  free(p);
  return OK;
}
void BFSTraverse(ALGraph G,void(*Visit)(char*))
{/*按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。*/
  int v,u,w;
  VertexType u1,w1;
  LinkQueue Q;
  for(v=0;v<G.vexnum;++v)
    visited[v]=FALSE; /* 置初值 */
  InitQueue(&Q); /* 置空的辅助队列Q */
  for(v=0;v<G.vexnum;v++) /* 如果是连通图,只v=0就遍历全图 */
    if(!visited[v]) /* v尚未访问 */
    {
      visited[v]=TRUE;
      Visit(G.vertices[v].data);
      EnQueue(&Q,v); /* v入队列 */
      while(!QueueEmpty(Q)) /* 队列不空 */
      {
        DeQueue(&Q,&u); /* 队头元素出队并置为u */
        strcpy(u1,*GetVex(G,u));
        for(w=FirstAdjVex(G,u1);w>=0;w=NextAdjVex(G,u1,strcpy(w1,*GetVex(G,w))))
          if(!visited[w]) /* w为u的尚未访问的邻接顶点 */
          {
            visited[w]=TRUE;
            Visit(G.vertices[w].data);
            EnQueue(&Q,w); /* w入队 */
          }
      }
    }
  printf("\n");
}
void Display(ALGraph G)
{ /* 输出图的邻接矩阵G */
  int i;
  ArcNode *p;
  switch(G.kind)
  {
    case DG: printf("有向图\n");
             break;
    case DN: printf("有向网\n");
             break;
    case AG: printf("无向图\n");
             break;
    case AN: printf("无向网\n");
  }
  printf("%d个顶点:\n",G.vexnum);
  for(i=0;i<G.vexnum;++i)
    printf("%s ",G.vertices[i].data);
  printf("\n%d条弧(边):\n",G.arcnum);
  for(i=0;i<G.vexnum;i++)
  {
    p=G.vertices[i].firstarc;
    while(p)
    {
      if(G.kind<=1) /* 有向 */
      {
        printf("%s→%s ",G.vertices[i].data,G.vertices[p->adjvex].data);
        if(G.kind==DN) /* 网 */
          printf(":%d ",*(p->info));
      }
      else /* 无向(避免输出两次) */
      {
        if(i<p->adjvex)
        {
          printf("%s-%s ",G.vertices[i].data,G.vertices[p->adjvex].data);
          if(G.kind==AN) /* 网 */
            printf(":%d ",*(p->info));
        }
      }
      p=p->nextarc;
    }
    printf("\n");
  }
}
void print(char *i)
{
  printf("%s ",i);
}
void main()
{
  int i,j,k,n;
  ALGraph g;
  VertexType v1,v2;
  printf("请选择有向图\n");
  CreateGraph(&g);
  Display(g);
  printf("删除一条边或弧,请输入待删除边或弧的弧尾 弧头:");
  scanf("%s%s",v1,v2);
  DeleteArc(&g,v1,v2);
  printf("修改顶点的值,请输入原值 新值: ");
  scanf("%s%s",v1,v2);
  PutVex(&g,v1,v2);
  printf("插入新顶点,请输入顶点的值: ");
  scanf("%s",v1);
  InsertVex(&g,v1);
  printf("插入与新顶点有关的弧或边,请输入弧或边数: ");
  scanf("%d",&n);
  for(k=0;k<n;k++)
  {
    printf("请输入另一顶点的值: ");
    scanf("%s",v2);
    printf("对于有向图,请输入另一顶点的方向(0:弧头 1:弧尾): ");
    scanf("%d",&j);
    if(j)
      InsertArc(&g,v2,v1);
    else
      InsertArc(&g,v1,v2);
  }
  Display(g);
  printf("删除顶点及相关的弧或边,请输入顶点的值: ");
  scanf("%s",v1);
  DeleteVex(&g,v1);
  Display(g);
  printf("深度优先搜索的结果:\n");
  DFSTraverse(g,print);
  printf("广度优先搜索的结果:\n");
  BFSTraverse(g,print);
  DestroyGraph(&g);
  printf("请顺序选择有向网,无向图,无向网\n");
  for(i=0;i<3;i++) /* 验证另外3种情况 */
  {
    CreateGraph(&g);
    Display(g);
    printf("插入新顶点,请输入顶点的值: ");
    scanf("%s",v1);
    InsertVex(&g,v1);
    printf("插入与新顶点有关的弧或边,请输入弧或边数: ");
    scanf("%d",&n);
    for(k=0;k<n;k++)
    {
      printf("请输入另一顶点的值: ");
      scanf("%s",v2);
      if(g.kind<=1) /* 有向 */
      {
        printf("对于有向图或网,请输入另一顶点的方向(0:弧头 1:弧尾): ");
        scanf("%d",&j);
        if(j)
          InsertArc(&g,v2,v1);
        else
          InsertArc(&g,v1,v2);
      }
      else /* 无向 */
        InsertArc(&g,v1,v2);
    }
    Display(g);
    printf("删除顶点及相关的弧或边,请输入顶点的值: ");
    scanf("%s",v1);
    DeleteVex(&g,v1);
    Display(g);
    DestroyGraph(&g);
  }
}

运行结果:

 retrun list 

1.7.3 有向图的十字链表存储表示

#include<stdio.h> /* EOF(=^Z或F6),NULL */
 #include<math.h> /* floor(),ceil(),abs() */
 #define TRUE 1
 #define FALSE 0
 #define OK 1
 #define ERROR 0
 typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
 typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
 typedef char InfoType;
 #define MAX_Info 80 /* 信息字符串最大长度+1 */
 #define MAX_VERTEX_NAME 3  /* 顶点字符串最大长度+1 */
 typedef char  VertexType[MAX_VERTEX_NAME];
 /* c7-3.h 有向图的十字链表存储表示 */
 #define MAX_VERTEX_NUM 20
 typedef struct ArcBox
 {
   int tailvex,headvex; /* 该弧的尾和头顶点的位置 */
   struct ArcBox *hlink,*tlink; /* 分别为弧头相同和弧尾相同的弧的链域 */
   InfoType *info; /* 该弧相关信息的指针(可无) */
 }ArcBox; /* 弧结点 */
 typedef struct
 {
   VertexType data;
   ArcBox *firstin,*firstout; /* 分别指向该顶点第一条入弧和出弧 */
 }VexNode; /* 顶点结点 */
 typedef struct
 {
   VexNode xlist[MAX_VERTEX_NUM]; /* 表头向量(数组) */
   int vexnum,arcnum; /* 有向图的当前顶点数和弧数 */
 }OLGraph;
 /* bo7-3.c 有向图的十字链表存储(存储结构由c7-3.h定义)的基本函数(15个) */
 int LocateVex(OLGraph G,VertexType u)
 { /* 返回顶点u在有向图G中的位置(序号),如不存在则返回-1 */
   int i;
   for(i=0;i<G.vexnum;++i) /* 用循环查找该结点 */
     if(!strcmp(G.xlist[i].data,u))
       return i;
   return -1;
 }

 Status CreateDG(OLGraph *G)
 { /* 采用十字链表存储表示,构造有向图G。算法7.3 */
   int i,j,k;
   int IncInfo;
   char str[MAX_Info];
   ArcBox *p;
   VertexType v1,v2;
   printf("请输入有向图的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
   scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
   printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_VERTEX_NAME);
   for(i=0;i<(*G).vexnum;++i)
   { /* 构造表头向量 */
     scanf("%s",&(*G).xlist[i].data); /* 输入顶点值 */
     (*G).xlist[i].firstin=NULL; /* 初始化指针 */
     (*G).xlist[i].firstout=NULL;
   }
   printf("请输入%d条弧的弧尾和弧头(空格为间隔):\n",(*G).arcnum);
   for(k=0;k<(*G).arcnum;++k)
   { /* 输入各弧并构造十字链表 */
     scanf("%s%s",&v1,&v2);
     i=LocateVex(*G,v1); /* 确定v1和v2在G中的位置 */
     j=LocateVex(*G,v2);
     p=(ArcBox *)malloc(sizeof(ArcBox)); /* 产生弧结点(假定有足够空间) */
     p->tailvex=i; /* 对弧结点赋值 */
     p->headvex=j;
     p->hlink=(*G).xlist[j].firstin; /* 完成在入弧和出弧链表表头的插入 */
     p->tlink=(*G).xlist[i].firstout;
     (*G).xlist[j].firstin=(*G).xlist[i].firstout=p;
     if(IncInfo)
     { /* 若弧含有相关信息,则输入 */
       printf("请输入该弧的相关信息(<%d个字符): ",MAX_Info);
       scanf("%s",str);
       p->info=(InfoType *)malloc((strlen(str)+1)*sizeof(InfoType));
       strcpy(p->info,str);
     }
     else /* 弧不含有相关信息 */
       p->info=NULL;
   }
   return OK;
 }

 void DestroyGraph(OLGraph *G)
 { /* 初始条件: 有向图G存在 */
   /* 操作结果: 销毁有向图G */
   int j;
   ArcBox *p,*q;
   for(j=0;j<(*G).vexnum;j++) /* 对所有顶点 */
   {
     p=(*G).xlist[j].firstout; /* 仅处理出弧 */
     while(p)
     {
       q=p;
       p=p->tlink;
       if(q->info)
         free(q->info);
       free(q);
     }
   }
   (*G).arcnum=0;
   (*G).vexnum=0;
 }

 VertexType* GetVex(OLGraph G,int v)
 { /* 初始条件:有向图G存在,v是G中某个顶点的序号。操作结果:返回v的值 */
   if(v>=G.vexnum||v<0)
     exit(ERROR);
   return &G.xlist[v].data;
 }

 Status PutVex(OLGraph *G,VertexType v,VertexType value)
 { /* 初始条件: 有向图G存在,v是G中某个顶点 */
   /* 操作结果: 对v赋新值value */
   int i;
   i=LocateVex(*G,v);
   if(i<0) /* v不是G的顶点 */
     return ERROR;
   strcpy((*G).xlist[i].data,value);
   return OK;
 }

 int FirstAdjVex(OLGraph G,VertexType v)
 { /* 初始条件: 有向图G存在,v是G中某个顶点 */
   /* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
   int i;
   ArcBox *p;
   i=LocateVex(G,v);
   p=G.xlist[i].firstout; /* p指向顶点v的第1个出弧 */
   if(p)
     return p->headvex;
   else
     return -1;
 }

 int NextAdjVex(OLGraph G,VertexType v,VertexType w)
 { /* 初始条件: 有向图G存在,v是G中某个顶点,w是v的邻接顶点 */
   /* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号, */
   /*           若w是v的最后一个邻接顶点,则返回-1 */
   int i,j;
   ArcBox *p;
   i=LocateVex(G,v); /* i是顶点v的序号 */
   j=LocateVex(G,w); /* j是顶点w的序号 */
   p=G.xlist[i].firstout; /* p指向顶点v的第1个出弧 */
   while(p&&p->headvex!=j)
     p=p->tlink;
   if(p) /* w不是v的最后一个邻接顶点 */
     p=p->tlink; /* p指向相对于w的下一个邻接顶点 */
   if(p) /* 有下一个邻接顶点 */
     return p->headvex;
   else
     return -1;
 }

 void InsertVex(OLGraph *G,VertexType v)
 { /* 初始条件: 有向图G存在,v和有向图G中顶点有相同特征 */
   /* 操作结果: 在有向图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做) */
   strcpy((*G). xlist[(*G). vexnum].data,v);
   (*G). xlist[(*G). vexnum].firstin=(*G). xlist[(*G). vexnum].firstout=NULL;
   (*G). vexnum++;
 }

 Status DeleteVex(OLGraph *G,VertexType v)
 { /* 初始条件: 有向图G存在,v是G中某个顶点 */
   /* 操作结果: 删除G中顶点v及其相关的弧 */
   int j,k;
   ArcBox *p,*q;
   k=LocateVex(*G,v); /* k是顶点v的序号 */
   if(k<0) /* v不是图G的顶点 */
     return ERROR;
   /* 以下删除顶点v的出弧 */
   for(j=0;j<(*G). vexnum;j++) /* 顶点v的出弧是其它顶点的入弧 */
   {
     if(j==k)
       continue;
     p=(*G). xlist[j].firstin; /* 在其它顶点的入弧链表中删除顶点v的出弧 */
     while(p)
       if(p->tailvex==k&&p==(*G). xlist[j].firstin) /* 待删结点为首结点 */
       {
         (*G). xlist[j].firstin=p->hlink;
         break;
       }
       else if(p->tailvex!=k) /* 没找到待删结点 */
       {
         q=p;
         p=p->hlink;
       }
       else /* 找到待删结点且不是首结点 */
       {
         q->hlink=p->hlink;
         break;
       }
   }
   p=(*G). xlist[k].firstout; /* 删除与顶点v有关的出弧 */
   while(p)
   {
     q=p->tlink; /* q指向p的下一个出弧 */
     if(p->info) /* 释放p */
       free(p->info);
     free(p);
     (*G). arcnum--;
     p=q;
   }
   /* 以下删除顶点v的入弧 */
   for(j=0;j<(*G). vexnum;j++) /* 顶点v的入弧是其它顶点的出弧 */
   {
     if(j==k)
       continue;
     p=(*G). xlist[j].firstout; /* 在其它顶点的出弧链表中删除顶点v的入弧 */
     while(p)
       if(p->headvex==k&&p==(*G). xlist[j].firstout) /* 待删结点为首结点 */
       {
         (*G). xlist[j].firstout=p->tlink;
         break;
       }
       else if(p->headvex!=k) /* 没找到待删结点 */
       {
         q=p;
         p=p->tlink;
       }
       else /* 找到待删结点且不是首结点 */
       {
         q->tlink=p->tlink;
         break;
       }
   }
   p=(*G). xlist[k].firstin; /* 删除与顶点v有关的入弧 */
   while(p)
   {
     q=p->hlink; /* q指向p的下一个入弧 */
     if(p->info) /* 释放p */
       free(p->info);
     free(p);
     (*G). arcnum--;
     p=q;
   }
   for(j=k+1;j<(*G). vexnum;j++) /* 序号>k的顶点依次向前移 */
     (*G). xlist[j-1]=(*G). xlist[j];
   (*G). vexnum--; /* 顶点数减1 */
   for(j=0;j<(*G). vexnum;j++) /* 结点序号>k的要减1 */
   {
     p=(*G). xlist[j].firstout; /* 处理出弧 */
     while(p)
     {
       if(p->tailvex>k)
         p->tailvex--; /* 序号-1 */
       if(p->headvex>k)
         p->headvex--; /* 序号-1 */
       p=p->tlink;
     }
   }
   return OK;
 }

 Status InsertArc(OLGraph *G,VertexType v,VertexType w)
 { /* 初始条件: 有向图G存在,v和w是G中两个顶点 */
   /* 操作结果: 在G中增添弧<v,w> */
   int i,j;
   int IncInfo;
   char str[MAX_Info];
   ArcBox *p;
   i=LocateVex(*G,v); /* 弧尾的序号 */
   j=LocateVex(*G,w); /* 弧头的序号 */
   if(i<0||j<0)
     return ERROR;
   p=(ArcBox *)malloc(sizeof(ArcBox)); /* 生成新结点 */
   p->tailvex=i; /* 给新结点赋值 */
   p->headvex=j;
   p->hlink=(*G). xlist[j].firstin; /* 插在入弧和出弧的链头 */
   p->tlink=(*G). xlist[i].firstout;
   (*G). xlist[j].firstin=(*G). xlist[i].firstout=p;
   (*G). arcnum++; /* 弧数加1 */
   printf("要插入的弧是否含有其它信息(是: 1,否: 0): ");
   scanf("%d",&IncInfo);
   if(IncInfo)
   {
     printf("请输入该弧的相关信息(<%d个字符): ",MAX_Info);
     scanf("%s",str);
     p->info=(InfoType *)malloc((strlen(str)+1)*sizeof(InfoType));
     strcpy(p->info,str);
   }
   else
     p->info=NULL;
   return OK;
 }

 Status DeleteArc(OLGraph *G,VertexType v,VertexType w)
 { /* 初始条件: 有向图G存在,v和w是G中两个顶点 */
   /* 操作结果: 在G中删除弧<v,w> */
   int i,j;
   ArcBox *p1,*p2;
   i=LocateVex(*G,v); /* 弧尾的序号 */
   j=LocateVex(*G,w); /* 弧头的序号 */
   if(i<0||j<0||i==j)
     return ERROR;
   p2=(*G). xlist[i].firstout; /* 将弧结点从出弧链表中删去 */
   if(p2&&p2->headvex==j) /* 第1个结点为待删除结点 */
     (*G). xlist[i].firstout=p2->tlink;
   else
   {
     while(p2&&p2->headvex!=j) /* 向后找 */
     {
       p1=p2;
       p2=p2->tlink;
     }
     if(p2) /* 没到表尾 */
       p1->tlink=p2->tlink;
   }
   p2=(*G). xlist[j].firstin; /* 将弧结点从入弧链表中删去 */
   if(p2&&p2->tailvex==i)
     (*G). xlist[j].firstin=p2->hlink;
   else
   {
     while(p2&&p2->tailvex!=i)
     {
       p1=p2;
       p2=p2->hlink;
     }
     if(p2) /* 没到表尾 */
       p1->hlink=p2->hlink;
   }
   if(p2->info) /* 释放弧结点 */
     free(p2->info);
   free(p2);
   (*G). arcnum--; /* 弧数减1 */
   return OK;
 }

 Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组 */
 Status(*VisitFunc)(VertexType); /* 函数变量 */
 void DFS(OLGraph G,int i) /* DFSTraverse()调用 */
 {
   ArcBox *p;
   visited[i]=TRUE; /* 访问标志数组置1(已被访问) */
   VisitFunc(G.xlist[i].data); /* 遍历第i个顶点 */
   p=G.xlist[i].firstout; /* p指向第i个顶点的出度 */
   while(p&&visited[p->headvex]) /* p没到表尾且该弧的头顶点已被访问 */
     p=p->tlink; /* 查找下一个结点 */
   if(p&&!visited[p->headvex]) /* 该弧的头顶点未被访问 */
     DFS(G,p->headvex); /* 递归调用DFS() */
 }

 void DFSTraverse(OLGraph G,Status(*Visit)(VertexType))
 { /* 初始条件: 有向图G存在,v是G中某个顶点,Visit是顶点的应用函数 */
   /* 操作结果: 从第1个顶点起,按深度优先递归遍历有向图G,并对每个顶点调用 */
   /*           函数Visit一次且仅一次。一旦Visit()失败,则操作失败 */
   int i;
   for(i=0;i<G.vexnum;i++)
     visited[i]=FALSE; /* 访问标志数组置初值(未被访问) */
   VisitFunc=Visit;
   for(i=0;i<G.vexnum;i++) /* 由序号0开始,继续查找未被访问过的顶点 */
     if(!visited[i])
       DFS(G,i);
   printf("\n");
 }

 typedef int QElemType;
 /* c3-3.h 队列的顺序存储结构(可用于循环队列和非循环队列) */
 #define MAXQSIZE 5 /* 最大队列长度(对于循环队列,最大队列长度要减1) */
 typedef struct
 {
   QElemType *base; /* 初始化的动态分配存储空间 */
   int front; /* 头指针,若队列不空,指向队列头元素 */
   int rear; /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
 }SqQueue;
 /* bo3-3.c 循环队列(存储结构由c3-3.h定义)的基本操作(9个) */
 Status InitQueue(SqQueue *Q)
 { /* 构造一个空队列Q */
   (*Q).base=(QElemType *)malloc(MAXQSIZE*sizeof(QElemType));
   if(!(*Q).base) /* 存储分配失败 */
     exit(OVERFLOW);
   (*Q).front=(*Q).rear=0;
   return OK;
 }
 Status QueueEmpty(SqQueue Q)
 { /* 若队列Q为空队列,则返回TRUE,否则返回FALSE */
   if(Q.front==Q.rear) /* 队列空的标志 */
     return TRUE;
   else
     return FALSE;
 }
 Status EnQueue(SqQueue *Q,QElemType e)
 { /* 插入元素e为Q的新的队尾元素 */
   if(((*Q).rear+1)%MAXQSIZE==(*Q).front) /* 队列满 */
     return ERROR;
   (*Q).base[(*Q).rear]=e;
   (*Q).rear=((*Q).rear+1)%MAXQSIZE;
   return OK;
 }

 Status DeQueue(SqQueue *Q,QElemType *e)
 { /* 若队列不空,则删除Q的队头元素,用e返回其值,并返回OK;否则返回ERROR */
   if((*Q).front==(*Q).rear) /* 队列空 */
     return ERROR;
   *e=(*Q).base[(*Q).front];
   (*Q).front=((*Q).front+1)%MAXQSIZE;
   return OK;
 }
 void BFSTraverse(OLGraph G,Status(*Visit)(VertexType))
 { /* 初始条件: 有向图G存在,Visit是顶点的应用函数。算法7.6 */
   /* 操作结果: 从第1个顶点起,按广度优先非递归遍历有向图G,并对每个顶点调用 */
   /*           函数Visit一次且仅一次。一旦Visit()失败,则操作失败。 */
   /*           使用辅助队列Q和访问标志数组visited */
   int v,u,w;
   VertexType u1,w1;
   SqQueue Q;
   for(v=0;v<G.vexnum;v++)
     visited[v]=FALSE;
   InitQueue(&Q);
   for(v=0;v<G.vexnum;v++)
     if(!visited[v])
     {
       visited[v]=TRUE;
       Visit(G.xlist[v].data);
       EnQueue(&Q,v);
       while(!QueueEmpty(Q))
       {
         DeQueue(&Q,&u);
         strcpy(u1,*GetVex(G,u));
         for(w=FirstAdjVex(G,u1);w>=0;w=NextAdjVex(G,u1,strcpy(w1,*GetVex(G,w))))
           if(!visited[w]) /* w为u的尚未访问的邻接顶点的序号 */
           {
             visited[w]=TRUE;
             Visit(G.xlist[w].data);
             EnQueue(&Q,w);
           }
       }
     }
   printf("\n");
 }

 void Display(OLGraph G)
 { /* 输出有向图G */
   int i;
   ArcBox *p;
   printf("共%d个顶点,%d条弧:\n",G.vexnum,G.arcnum);
   for(i=0;i<G.vexnum;i++)
   {
     printf("顶点%s: 入度: ",G.xlist[i].data);
     p=G.xlist[i].firstin;
     while(p)
     {
       printf("%s ",G.xlist[p->tailvex].data);
       p=p->hlink;
     }
     printf("出度: ");
     p=G.xlist[i].firstout;
     while(p)
     {
       printf("%s ",G.xlist[p->headvex].data);
       if(p->info) /* 该弧有相关信息 */
         printf("弧信息: %s ",p->info);
       p=p->tlink;
     }
     printf("\n");
   }
 }
 Status visit(VertexType v)
 {
   printf("%s ",v);
   return OK;
 }

 void main()
 {
   int j,k,n;
   OLGraph g;
   VertexType v1,v2;
   CreateDG(&g);
   Display(g);
   printf("修改顶点的值,请输入原值 新值: ");
   scanf("%s%s",v1,v2);
   PutVex(&g,v1,v2);
   printf("插入新顶点,请输入顶点的值: ");
   scanf("%s",v1);
   InsertVex(&g,v1);
   printf("插入与新顶点有关的弧,请输入弧数: ");
   scanf("%d",&n);
   for(k=0;k<n;k++)
   {
     printf("请输入另一顶点的值 另一顶点的方向(0:弧头 1:弧尾): ");
     scanf("%s%d",v2,&j);
     if(j)
       InsertArc(&g,v2,v1);
     else
       InsertArc(&g,v1,v2);
   }
   Display(g);
   printf("删除一条弧,请输入待删除弧的弧尾 弧头:");
   scanf("%s%s",v1,v2);
   DeleteArc(&g,v1,v2);
   Display(g);
   printf("删除顶点及相关的弧,请输入顶点的值: ");
   scanf("%s",v1);
   DeleteVex(&g,v1);
   Display(g);
   printf("深度优先搜索的结果:\n");
   DFSTraverse(g,visit);
   printf("广度优先搜索的结果:\n");
   BFSTraverse(g,visit);
   DestroyGraph(&g);
 }

运行结果:

retrun list 

1.7.4 无向图的邻接多重表存储表示

#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 3 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 80 /* 相关信息字符串的最大长度+1 */
typedef char InfoType;
typedef char VertexType[MAX_NAME]; /* 字符串类型 */
#define MAX_VERTEX_NUM 20
typedef enum{unvisited,visited}VisitIf;
typedef struct EBox
{
  VisitIf mark; /* 访问标记 */
  int ivex,jvex; /* 该边依附的两个顶点的位置 */
  struct EBox *ilink,*jlink; /* 分别指向依附这两个顶点的下一条边 */
  InfoType *info; /* 该边信息指针 */
}EBox;
typedef struct
{
  VertexType data;
  EBox *firstedge; /* 指向第一条依附该顶点的边 */
}VexBox;
typedef struct
{
  VexBox adjmulist[MAX_VERTEX_NUM];
  int vexnum,edgenum; /* 无向图的当前顶点数和边数 */
}AMLGraph;
int LocateVex(AMLGraph G,VertexType u)
{ /* 初始条件: 无向图G存在,u和G中顶点有相同特征 */
  /* 操作结果: 若G中存在顶点u,则返回该顶点在无向图中位置;否则返回-1 */
  int i;
  for(i=0;i<G.vexnum;++i)
    if(strcmp(u,G.adjmulist[i].data)==0)
      return i;
  return -1;
}
Status CreateGraph(AMLGraph *G)
{ /* 采用邻接多重表存储结构,构造无向图G */
  int i,j,k,l,IncInfo;
  char s[MAX_INFO];
  VertexType va,vb;
  EBox *p;
  printf("请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).edgenum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
  {
    scanf("%s",(*G).adjmulist[i].data);
    (*G).adjmulist[i].firstedge=NULL;
  }
  printf("请顺序输入每条边的两个端点(以空格作为间隔):\n");
  for(k=0;k<(*G).edgenum;++k) /* 构造表结点链表 */
  {
    scanf("%s%s%*c",va,vb); /* %*c吃掉回车符 */
    i=LocateVex(*G,va); /* 一端 */
    j=LocateVex(*G,vb); /* 另一端 */
    p=(EBox*)malloc(sizeof(EBox));
    p->mark=unvisited; /* 设初值 */
    p->ivex=i;
    p->jvex=j;
    p->info=NULL;
    p->ilink=(*G).adjmulist[i].firstedge; /* 插在表头 */
    (*G).adjmulist[i].firstedge=p;
    p->jlink=(*G).adjmulist[j].firstedge; /* 插在表头 */
    (*G).adjmulist[j].firstedge=p;
    if(IncInfo) /* 边有相关信息 */
    {
      printf("请输入该弧的相关信息(<%d个字符):",MAX_INFO);
      gets(s);
      l=strlen(s);
      if(l)
      {
        p->info=(char*)malloc((l+1)*sizeof(char));
        strcpy(p->info,s);
      }
    }
  }
  return OK;
}
VertexType* GetVex(AMLGraph G,int v)
{ /* 初始条件: 无向图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
  if(v>=G.vexnum||v<0)
    exit(ERROR);
  return &G.adjmulist[v].data;
}
Status PutVex(AMLGraph *G,VertexType v,VertexType value)
{ /* 初始条件: 无向图G存在,v是G中某个顶点 */
  /* 操作结果: 对v赋新值value */
  int i;
  i=LocateVex(*G,v);
  if(i<0) /* v不是G的顶点 */
    return ERROR;
  strcpy((*G).adjmulist[i].data,value);
  return OK;
}

int FirstAdjVex(AMLGraph G,VertexType v)
{ /* 初始条件: 无向图G存在,v是G中某个顶点 */
  /* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
  int i;
  i=LocateVex(G,v);
  if(i<0)
    return -1;
  if(G.adjmulist[i].firstedge) /* v有邻接顶点 */
    if(G.adjmulist[i].firstedge->ivex==i)
      return G.adjmulist[i].firstedge->jvex;
    else
      return G.adjmulist[i].firstedge->ivex;
  else
    return -1;
}

int NextAdjVex(AMLGraph G,VertexType v,VertexType w)
{ /* 初始条件: 无向图G存在,v是G中某个顶点,w是v的邻接顶点 */
  /* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。 */
  /*           若w是v的最后一个邻接点,则返回-1 */
  int i,j;
  EBox *p;
  i=LocateVex(G,v); /* i是顶点v的序号 */
  j=LocateVex(G,w); /* j是顶点w的序号 */
  if(i<0||j<0) /* v或w不是G的顶点 */
    return -1;
  p=G.adjmulist[i].firstedge; /* p指向顶点v的第1条边 */
  while(p)
    if(p->ivex==i&&p->jvex!=j) /* 不是邻接顶点w(情况1) */
      p=p->ilink; /* 找下一个邻接顶点 */
    else if(p->jvex==i&&p->ivex!=j) /* 不是邻接顶点w(情况2) */
      p=p->jlink; /* 找下一个邻接顶点 */
    else /* 是邻接顶点w */
      break;
  if(p&&p->ivex==i&&p->jvex==j) /* 找到邻接顶点w(情况1) */
  {
    p=p->ilink;
    if(p&&p->ivex==i)
      return p->jvex;
    else if(p&&p->jvex==i)
      return p->ivex;
  }
  if(p&&p->ivex==j&&p->jvex==i) /* 找到邻接顶点w(情况2) */
  {
    p=p->jlink;
    if(p&&p->ivex==i)
      return p->jvex;
    else if(p&&p->jvex==i)
      return p->ivex;
  }
  return -1;
}

Status InsertVex(AMLGraph *G,VertexType v)
{ /* 初始条件: 无向图G存在,v和G中顶点有相同特征 */
  /* 操作结果: 在G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做) */
  if((*G).vexnum==MAX_VERTEX_NUM) /* 结点已满,不能插入 */
    return ERROR;
  if(LocateVex(*G,v)>=0) /* 结点已存在,不能插入 */
    return ERROR;
  strcpy((*G).adjmulist[(*G).vexnum].data,v);
  (*G).adjmulist[(*G).vexnum].firstedge=NULL;
  (*G).vexnum++;
  return OK;
}

Status DeleteArc(AMLGraph *G,VertexType v,VertexType w)
{ /* 初始条件: 无向图G存在,v和w是G中两个顶点 */
  /* 操作结果: 在G中删除弧<v,w> */
  int i,j;
  EBox *p,*q;
  i=LocateVex(*G,v);
  j=LocateVex(*G,w);
  if(i<0||j<0||i==j)
    return ERROR;  /* 图中没有该点或弧 */
  /* 以下使指向待删除边的第1个指针绕过这条边 */
  p=(*G).adjmulist[i].firstedge; /* p指向顶点v的第1条边 */
  if(p&&p->jvex==j) /* 第1条边即为待删除边(情况1) */
    (*G).adjmulist[i].firstedge=p->ilink;
  else if(p&&p->ivex==j) /* 第1条边即为待删除边(情况2) */
    (*G).adjmulist[i].firstedge=p->jlink;
  else /* 第1条边不是待删除边 */
  {
    while(p) /* 向后查找弧<v,w> */
    {
      if(p->ivex==i&&p->jvex!=j) /* 不是待删除边 */
      {
        q=p;
        p=p->ilink; /* 找下一个邻接顶点 */
      }
      else if(p->jvex==i&&p->ivex!=j) /* 不是待删除边 */
      {
        q=p;
        p=p->jlink; /* 找下一个邻接顶点 */
      }
      else /* 是邻接顶点w */
        break;
    }
    if(!p) /* 没找到该边 */
      return ERROR;
    if(p->ivex==i&&p->jvex==j) /* 找到弧<v,w>(情况1) */
      if(q->ivex==i)
        q->ilink=p->ilink;
      else
        q->jlink=p->ilink;
    else if(p->ivex==j&&p->jvex==i) /* 找到弧<v,w>(情况2) */
      if(q->ivex==i)
        q->ilink=p->jlink;
      else
        q->jlink=p->jlink;
  }
  /* 以下由另一顶点起找待删除边且删除之 */
  p=(*G).adjmulist[j].firstedge; /* p指向顶点w的第1条边 */
  if(p->jvex==i) /* 第1条边即为待删除边(情况1) */
  {
    (*G).adjmulist[j].firstedge=p->ilink;
    if(p->info) /* 有相关信息 */
      free(p->info);
    free(p);
  }
  else if(p->ivex==i) /* 第1条边即为待删除边(情况2) */
  {
    (*G).adjmulist[j].firstedge=p->jlink;
    if(p->info) /* 有相关信息 */
      free(p->info);
    free(p);
  }
  else /* 第1条边不是待删除边 */
  {
    while(p) /* 向后查找弧<v,w> */
      if(p->ivex==j&&p->jvex!=i) /* 不是待删除边 */
      {
        q=p;
        p=p->ilink; /* 找下一个邻接顶点 */
      }
      else if(p->jvex==j&&p->ivex!=i) /* 不是待删除边 */
      {
        q=p;
        p=p->jlink; /* 找下一个邻接顶点 */
      }
      else /* 是邻接顶点v */
        break;
    if(p->ivex==i&&p->jvex==j) /* 找到弧<v,w>(情况1) */
    {
      if(q->ivex==j)
        q->ilink=p->jlink;
      else
        q->jlink=p->jlink;
      if(p->info) /* 有相关信息 */
        free(p->info);
      free(p);
    }
    else if(p->ivex==j&&p->jvex==i) /* 找到弧<v,w>(情况2) */
    {
      if(q->ivex==j)
        q->ilink=p->ilink;
      else
        q->jlink=p->ilink;
      if(p->info) /* 有相关信息 */
        free(p->info);
      free(p);
    }
  }
  (*G).edgenum--;
  return OK;
}

Status DeleteVex(AMLGraph *G,VertexType v)
{ /* 初始条件: 无向图G存在,v是G中某个顶点 */
  /* 操作结果: 删除G中顶点v及其相关的边 */
  int i,j;
  VertexType w;
  EBox *p;
  i=LocateVex(*G,v); /* i为待删除顶点的序号 */
  if(i<0)
    return ERROR;
  for(j=0;j<(*G).vexnum;j++) /* 删除与顶点v相连的边(如果有的话) */
  {
    if(j==i)
      continue;
    strcpy(w,*GetVex(*G,j)); /* w是第j个顶点的值 */
    DeleteArc(G,v,w);
  }
  for(j=i+1;j<(*G).vexnum;j++) /* 排在顶点v后面的顶点的序号减1 */
    (*G).adjmulist[j-1]=(*G).adjmulist[j];
  (*G).vexnum--; /* 顶点数减1 */
  for(j=i;j<(*G).vexnum;j++) /* 修改顶点的序号 */
  {
    p=(*G).adjmulist[j].firstedge;
    if(p)
    {
      if(p->ivex==j+1)
      {
        p->ivex--;
        p=p->ilink;
      }
      else
      {
        p->jvex--;
        p=p->jlink;
      }
    }
  }
  return OK;
}
void DestroyGraph(AMLGraph *G)
{
  int i;
  for(i=(*G).vexnum-1;i>=0;i--)
    DeleteVex(G,(*G).adjmulist[i].data);
}
Status InsertArc(AMLGraph *G,VertexType v,VertexType w)
{ /* 初始条件: 无向图G存在,v和W是G中两个顶点 */
  /* 操作结果: 在G中增添弧<v,w> */
  int i,j,l,IncInfo;
  char s[MAX_INFO];
  EBox *p;
  i=LocateVex(*G,v); /* 一端 */
  j=LocateVex(*G,w); /* 另一端 */
  if(i<0||j<0)
    return ERROR;
  p=(EBox*)malloc(sizeof(EBox));
  p->mark=unvisited;
  p->ivex=i;
  p->jvex=j;
  p->info=NULL;
  p->ilink=(*G).adjmulist[i].firstedge; /* 插在表头 */
  (*G).adjmulist[i].firstedge=p;
  p->jlink=(*G).adjmulist[j].firstedge; /* 插在表头 */
  (*G).adjmulist[j].firstedge=p;
  printf("该边是否有相关信息(1:有 0:无): ");
  scanf("%d%*c",&IncInfo); /* 吃掉回车符 */
  if(IncInfo) /* 边有相关信息 */
  {
    printf("请输入该边的相关信息(<%d个字符):",MAX_INFO);
    gets(s);
    l=strlen(s);
    if(l)
    {
      p->info=(char*)malloc((l+1)*sizeof(char));
      strcpy(p->info,s);
    }
  }
  (*G).edgenum++;
  return OK;
}
Boolean visite[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
Status(*VisitFunc)(VertexType v);
void DFS(AMLGraph G,int v)
{
  int j;
  EBox *p;
  VisitFunc(G.adjmulist[v].data);
  visite[v]=TRUE;
  p=G.adjmulist[v].firstedge;
  while(p)
  {
    j=p->ivex==v?p->jvex:p->ivex;
    if(!visite[j])
      DFS(G,j);
    p=p->ivex==v?p->ilink:p->jlink;
  }
}
void DFSTraverse(AMLGraph G,Status(*visit)(VertexType))
{ /* 初始条件: 图G存在,Visit是顶点的应用函数。*/
  /* 操作结果: 从第1个顶点起,深度优先遍历图G,并对每个顶点调用函数Visit */
  /*           一次且仅一次。一旦Visit()失败,则操作失败 */
  int v;
  VisitFunc=visit;
  for(v=0;v<G.vexnum;v++)
    visite[v]=FALSE;
  for(v=0;v<G.vexnum;v++)
    if(!visite[v])
      DFS(G,v);
  printf("\n");
}
typedef int QElemType; /* 队列类型 */
typedef struct QNode
{
  QElemType data;
  struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
  QueuePtr front,rear; /* 队头、队尾指针 */
}LinkQueue;
Status InitQueue(LinkQueue *Q)
{ /* 构造一个空队列Q */
  (*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));
  if(!(*Q).front)
    exit(OVERFLOW);
  (*Q).front->next=NULL;
  return OK;
}
Status QueueEmpty(LinkQueue Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */
  if(Q.front==Q.rear)
    return TRUE;
  else
    return FALSE;
}
Status EnQueue(LinkQueue *Q,QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
  QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
  if(!p) /* 存储分配失败 */
    exit(OVERFLOW);
  p->data=e;
  p->next=NULL;
  (*Q).rear->next=p;
  (*Q).rear=p;
  return OK;
}
Status DeQueue(LinkQueue *Q,QElemType *e)
{ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
  QueuePtr p;
  if((*Q).front==(*Q).rear)
    return ERROR;
  p=(*Q).front->next;
  *e=p->data;
  (*Q).front->next=p->next;
  if((*Q).rear==p)
    (*Q).rear=(*Q).front;
  free(p);
  return OK;
}
void BFSTraverse(AMLGraph G,Status(*Visit)(VertexType))
{ /* 初始条件: 图G存在,Visit是顶点的应用函数。*/
  /* 操作结果: 从第1个顶点起,按广度优先非递归遍历图G,并对每个顶点调用函数 */
  /*           Visit一次且仅一次。一旦Visit()失败,则操作失败。 */
  /*           使用辅助队列Q和访问标志数组visite */
  int v,u,w;
  VertexType w1,u1;
  LinkQueue Q;
  for(v=0;v<G.vexnum;v++)
    visite[v]=FALSE; /* 置初值 */
  InitQueue(&Q); /* 置空的辅助队列Q */
  for(v=0;v<G.vexnum;v++)
    if(!visite[v]) /* v尚未访问 */
    {
      visite[v]=TRUE; /* 设置访问标志为TRUE(已访问) */
      Visit(G.adjmulist[v].data);
      EnQueue(&Q,v); /* v入队列 */
      while(!QueueEmpty(Q)) /* 队列不空 */
      {
        DeQueue(&Q,&u); /* 队头元素出队并置为u */
        strcpy(u1,*GetVex(G,u));
        for(w=FirstAdjVex(G,u1);w>=0;w=NextAdjVex(G,u1,strcpy(w1,*GetVex(G,w))))
          if(!visite[w]) /* w为u的尚未访问的邻接顶点的序号 */
          {
            visite[w]=TRUE;
            Visit(G.adjmulist[w].data);
            EnQueue(&Q,w);
          }
      }
    }
  printf("\n");
}
void MarkUnvizited(AMLGraph G)
{ /* 置边的访问标记为未被访问 */
  int i;
  EBox *p;
  for(i=0;i<G.vexnum;i++)
  {
    p=G.adjmulist[i].firstedge;
    while(p)
    {
      p->mark=unvisited;
      if(p->ivex==i)
        p=p->ilink;
      else
        p=p->jlink;
    }
  }
}
void Display(AMLGraph G)
{ /* 输出无向图的邻接多重表G */
  int i;
  EBox *p;
  MarkUnvizited(G); /* 置边的访问标记为未被访问 */
  printf("%d个顶点:\n",G.vexnum);
  for(i=0;i<G.vexnum;++i)
    printf("%s ",G.adjmulist[i].data);
  printf("\n%d条边:\n",G.edgenum);
  for(i=0;i<G.vexnum;i++)
  {
    p=G.adjmulist[i].firstedge;
    while(p)
      if(p->ivex==i) /* 边的i端与该顶点有关 */
      {
        if(!p->mark) /* 只输出一次 */
        {
          printf("%s-%s ",G.adjmulist[i].data,G.adjmulist[p->jvex].data);
          p->mark=visited;
          if(p->info) /* 输出附带信息 */
            printf("相关信息: %s ",p->info);
        }
        p=p->ilink;
      }
      else /* 边的j端与该顶点有关 */
      {
        if(!p->mark) /* 只输出一次 */
        {
          printf("%s-%s ",G.adjmulist[p->ivex].data,G.adjmulist[i].data);
          p->mark=visited;
          if(p->info) /* 输出附带信息 */
            printf("相关信息: %s ",p->info);
        }
        p=p->jlink;
      }
    printf("\n");
  }
}
Status visit(VertexType v)
{
  printf("%s ",v);
  return OK;
}
void main()
{
  int k,n;
  AMLGraph g;
  VertexType v1,v2;
  CreateGraph(&g);
  Display(g);
  printf("修改顶点的值,请输入原值 新值: ");
  scanf("%s%s",v1,v2);
  PutVex(&g,v1,v2);
  printf("插入新顶点,请输入顶点的值: ");
  scanf("%s",v1);
  InsertVex(&g,v1);
  printf("插入与新顶点有关的边,请输入边数: ");
  scanf("%d",&n);
  for(k=0;k<n;k++)
  {
    printf("请输入另一顶点的值: ");
    scanf("%s",v2);
    InsertArc(&g,v1,v2);
  }
  Display(g);
  printf("深度优先搜索的结果:\n");
  DFSTraverse(g,visit);
  printf("广度优先搜索的结果:\n");
  BFSTraverse(g,visit);
  DestroyGraph(&g);
}

运行结果:

 retrun list 

1.7.5 最小生成树

#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int VRType;
typedef char InfoType;
#define MAX_NAME 3 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 20 /* 相关信息字符串的最大长度+1 */
typedef char VertexType[MAX_NAME];
#define INFINITY INT_MAX /* 用整型最大值代替∞ */
#define MAX_VERTEX_NUM 20 /* 最大顶点个数 */
typedef enum{DG,DN,AG,AN}GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct
{
  VRType adj; /* 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; */
       /* 对带权图,c则为权值类型 */
  InfoType *info; /* 该弧相关信息的指针(可无) */
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct
{
  VertexType vexs[MAX_VERTEX_NUM]; /* 顶点向量 */
  AdjMatrix arcs; /* 邻接矩阵 */
  int vexnum,arcnum; /* 图的当前顶点数和弧数 */
  GraphKind kind; /* 图的种类标志 */
}MGraph;
/*图的数组(邻接矩阵)存储(存储结构由c7-1.h定义)的基本操作*/
int LocateVex(MGraph G,VertexType u)
{ /* 初始条件:图G存在,u和G中顶点有相同特征 */
  /* 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
  int i;
  for(i=0;i<G.vexnum;++i)
    if(strcmp(u,G.vexs[i])==0)
      return i;
  return -1;
}
Status CreateAN(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造无向网G。*/
  int i,j,k,w,IncInfo;
  char s[MAX_INFO],*info;
  VertexType va,vb;
  printf("请输入无向网G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    scanf("%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=INFINITY; /* 网 */
      (*G).arcs[i][j].info=NULL;
    }
  printf("请输入%d条边的顶点1 顶点2 权值(以空格作为间隔): \n",(*G).arcnum);
  for(k=0;k<(*G).arcnum;++k)
  {
    scanf("%s%s%d%*c",va,vb,&w); /* %*c吃掉回车符 */
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=(*G).arcs[j][i].adj=w; /* 无向 */
    if(IncInfo)
    {
      printf("请输入该边的相关信息(<%d个字符): ",MAX_INFO);
      gets(s);
      w=strlen(s);
      if(w)
      {
        info=(char*)malloc((w+1)*sizeof(char));
        strcpy(info,s);
        (*G).arcs[i][j].info=(*G).arcs[j][i].info=info; /* 无向 */
      }
    }
  }
  (*G).kind=AN;
  return OK;
}
typedef struct
{ /* 记录从顶点集U到V-U的代价最小的边的辅助数组定义 */
  VertexType adjvex;
  VRType lowcost;
}minside[MAX_VERTEX_NUM];
int minimum(minside SZ,MGraph G)
{ /* 求closedge.lowcost的最小正值 */
  int i=0,j,k,min;
  while(!SZ[i].lowcost)
    i++;
  min=SZ[i].lowcost; /* 第一个不为0的值 */
  k=i;
  for(j=i+1;j<G.vexnum;j++)
    if(SZ[j].lowcost>0)
      if(min>SZ[j].lowcost)
      {
        min=SZ[j].lowcost;
        k=j;
      }
  return k;
}
void MiniSpanTree_PRIM(MGraph G,VertexType u)
{ /* 用普里姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边*/
  int i,j,k;
  minside closedge;
  k=LocateVex(G,u);
  for(j=0;j<G.vexnum;++j) /* 辅助数组初始化 */
  {
    if(j!=k)
    {
      strcpy(closedge[j].adjvex,u);
      closedge[j].lowcost=G.arcs[k][j].adj;
    }
  }
  closedge[k].lowcost=0; /* 初始,U={u} */
  printf("最小代价生成树的各条边为:\n");
  for(i=1;i<G.vexnum;++i)
  { /* 选择其余G.vexnum-1个顶点 */
    k=minimum(closedge,G); /* 求出T的下一个结点:第K顶点 */
    printf("(%s-%s)\n",closedge[k].adjvex,G.vexs[k]); /* 输出生成树的边 */
    closedge[k].lowcost=0; /* 第K顶点并入U集 */
    for(j=0;j<G.vexnum;++j)
      if(G.arcs[k][j].adj<closedge[j].lowcost)
      { /* 新顶点并入U集后重新选择最小边 */
        strcpy(closedge[j].adjvex,G.vexs[k]);
        closedge[j].lowcost=G.arcs[k][j].adj;
      }
  }
}
void main()
{
  MGraph G;
  CreateAN(&G);
  MiniSpanTree_PRIM(G,G.vexs[0]);
}

运行结果:

1.7.6 关节点和重连通分量

#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
/* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 2 /* 顶点字符串的最大长度+1 */
typedef int InfoType;
typedef char VertexType[MAX_NAME]; /* 字符串类型 */
#define MAX_VERTEX_NUM 20
typedef enum{DG,DN,AG,AN}GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct ArcNode
{
  int adjvex; /* 该弧所指向的顶点的位置 */
  struct ArcNode *nextarc; /* 指向下一条弧的指针 */
  InfoType *info; /* 网的权值指针) */
}ArcNode; /* 表结点 */
typedef struct
{
  VertexType data; /* 顶点信息 */
  ArcNode *firstarc; /* 第一个表结点的地址,指向第一条依附该顶点的弧的指针 */
}VNode,AdjList[MAX_VERTEX_NUM]; /* 头结点 */
typedef struct
{
  AdjList vertices;
  int vexnum,arcnum; /* 图的当前顶点数和弧数 */
  int kind; /* 图的种类标志 */
}ALGraph;
int LocateVex(ALGraph G,VertexType u)
{ /* 初始条件: 图G存在,u和G中顶点有相同特征 */
  /* 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
  int i;
  for(i=0;i<G.vexnum;++i)
    if(strcmp(u,G.vertices[i].data)==0)
      return i;
  return -1;
}
Status CreateGraph(ALGraph *G)
{ /* 采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图) */
  int i,j,k;
  int w; /* 权值 */
  VertexType va,vb;
  ArcNode *p;
  printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
  scanf("%d",&(*G).kind);
  printf("请输入图的顶点数,边数: ");
  scanf("%d,%d",&(*G).vexnum,&(*G).arcnum);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
  {
    scanf("%s",(*G).vertices[i].data);
    (*G).vertices[i].firstarc=NULL;
  }
  if((*G).kind==1||(*G).kind==3) /* 网 */
    printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");
  else /* 图 */
    printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");
  for(k=0;k<(*G).arcnum;++k) /* 构造表结点链表 */
  {
    if((*G).kind==1||(*G).kind==3) /* 网 */
      scanf("%d%s%s",&w,va,vb);
    else /* 图 */
      scanf("%s%s",va,vb);
    i=LocateVex(*G,va); /* 弧尾 */
    j=LocateVex(*G,vb); /* 弧头 */
    p=(ArcNode*)malloc(sizeof(ArcNode));
    p->adjvex=j;
    if((*G).kind==1||(*G).kind==3) /* 网 */
    {
      p->info=(int *)malloc(sizeof(int));
      *(p->info)=w;
    }
    else
      p->info=NULL; /* 图 */
    p->nextarc=(*G).vertices[i].firstarc; /* 插在表头 */
    (*G).vertices[i].firstarc=p;
    if((*G).kind>=2) /* 无向图或网,产生第二个表结点 */
    {
      p=(ArcNode*)malloc(sizeof(ArcNode));
      p->adjvex=i;
      if((*G).kind==3) /* 无向网 */
      {
        p->info=(int*)malloc(sizeof(int));
        *(p->info)=w;
      }
      else
        p->info=NULL; /* 无向图 */
      p->nextarc=(*G).vertices[j].firstarc; /* 插在表头 */
      (*G).vertices[j].firstarc=p;
    }
  }
  return OK;
}
VertexType* GetVex(ALGraph G,int v)
{ /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
  if(v>=G.vexnum||v<0)
    exit(ERROR);
  return &G.vertices[v].data;
}
int FirstAdjVex(ALGraph G,VertexType v)
{ /* 初始条件: 图G存在,v是G中某个顶点 */
  /* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
  ArcNode *p;
  int v1;
  v1=LocateVex(G,v); /* v1为顶点v在图G中的序号 */
  p=G.vertices[v1].firstarc;
  if(p)
    return p->adjvex;
  else
    return -1;
}
int NextAdjVex(ALGraph G,VertexType v,VertexType w)
{ /* 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点 */
  /* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。 */
  /*           若w是v的最后一个邻接点,则返回-1 */
  ArcNode *p;
  int v1,w1;
  v1=LocateVex(G,v); /* v1为顶点v在图G中的序号 */
  w1=LocateVex(G,w); /* w1为顶点w在图G中的序号 */
  p=G.vertices[v1].firstarc;
  while(p&&p->adjvex!=w1) /* 指针p不空且所指表结点不是w */
    p=p->nextarc;
  if(!p||!p->nextarc) /* 没找到w或w是最后一个邻接点 */
    return -1;
  else /* p->adjvex==w */
    return p->nextarc->adjvex; /* 返回v的(相对于w的)下一个邻接顶点的序号 */
}
Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
void(*VisitFunc)(char* v); /* 函数变量(全局量) */
void DFS(ALGraph G,int v)
{ /* 从第v个顶点出发递归地深度优先遍历图G。*/
  int w;
  VertexType v1,w1;
  strcpy(v1,*GetVex(G,v));
  visited[v]=TRUE; /* 设置访问标志为TRUE(已访问) */
  VisitFunc(G.vertices[v].data); /* 访问第v个顶点 */
  for(w=FirstAdjVex(G,v1);w>=0;w=NextAdjVex(G,v1,strcpy(w1,*GetVex(G,w))))
    if(!visited[w])
      DFS(G,w); /* 对v的尚未访问的邻接点w递归调用DFS */
}
typedef int QElemType; /* 队列类型 */
typedef struct QNode
{
  QElemType data;
  struct QNode *next;
}QNode,*QueuePtr;

typedef struct
{
  QueuePtr front,rear; /* 队头、队尾指针 */
}LinkQueue;
Status InitQueue(LinkQueue *Q)
{ /* 构造一个空队列Q */
  (*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));
  if(!(*Q).front)
    exit(OVERFLOW);
  (*Q).front->next=NULL;
  return OK;
}
Status QueueEmpty(LinkQueue Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */
  if(Q.front==Q.rear)
    return TRUE;
  else
    return FALSE;
}
Status EnQueue(LinkQueue *Q,QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
  QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
  if(!p) /* 存储分配失败 */
    exit(OVERFLOW);
  p->data=e;
  p->next=NULL;
  (*Q).rear->next=p;
  (*Q).rear=p;
  return OK;
}
Status DeQueue(LinkQueue *Q,QElemType *e)
{ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
  QueuePtr p;
  if((*Q).front==(*Q).rear)
    return ERROR;
  p=(*Q).front->next;
  *e=p->data;
  (*Q).front->next=p->next;
  if((*Q).rear==p)
    (*Q).rear=(*Q).front;
  free(p);
  return OK;
}
void BFSTraverse(ALGraph G,void(*Visit)(char*))
{/*按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。*/
  int v,u,w;
  VertexType u1,w1;
  LinkQueue Q;
  for(v=0;v<G.vexnum;++v)
    visited[v]=FALSE; /* 置初值 */
  InitQueue(&Q); /* 置空的辅助队列Q */
  for(v=0;v<G.vexnum;v++) /* 如果是连通图,只v=0就遍历全图 */
    if(!visited[v]) /* v尚未访问 */
    {
      visited[v]=TRUE;
      Visit(G.vertices[v].data);
      EnQueue(&Q,v); /* v入队列 */
      while(!QueueEmpty(Q)) /* 队列不空 */
      {
        DeQueue(&Q,&u); /* 队头元素出队并置为u */
        strcpy(u1,*GetVex(G,u));
        for(w=FirstAdjVex(G,u1);w>=0;w=NextAdjVex(G,u1,strcpy(w1,*GetVex(G,w))))
          if(!visited[w]) /* w为u的尚未访问的邻接顶点 */
          {
            visited[w]=TRUE;
            Visit(G.vertices[w].data);
            EnQueue(&Q,w); /* w入队 */
          }
      }
    }
  printf("\n");
}
void Display(ALGraph G)
{ /* 输出图的邻接矩阵G */
  int i;
  ArcNode *p;
  switch(G.kind)
  {
    case DG: printf("有向图\n");
             break;
    case DN: printf("有向网\n");
             break;
    case AG: printf("无向图\n");
             break;
    case AN: printf("无向网\n");
  }
  printf("%d个顶点:\n",G.vexnum);
  for(i=0;i<G.vexnum;++i)
    printf("%s ",G.vertices[i].data);
  printf("\n%d条弧(边):\n",G.arcnum);
  for(i=0;i<G.vexnum;i++)
  {
    p=G.vertices[i].firstarc;
    while(p)
    {
      if(G.kind<=1) /* 有向 */
      {
        printf("%s→%s ",G.vertices[i].data,G.vertices[p->adjvex].data);
        if(G.kind==DN) /* 网 */
          printf(":%d ",*(p->info));
      }
      else /* 无向(避免输出两次) */
      {
        if(i<p->adjvex)
        {
          printf("%s-%s ",G.vertices[i].data,G.vertices[p->adjvex].data);
          if(G.kind==AN) /* 网 */
            printf(":%d ",*(p->info));
        }
      }
      p=p->nextarc;
    }
    printf("\n");
  }
}
int count; /* 全局量count对访问计数 */
int low[MAX_VERTEX_NUM];
void DFSArticul(ALGraph G,int v0)
{ /* 从第v0个顶点出发深度优先遍历图G,查找并输出关节点。*/
  int min,w;
  ArcNode *p;
  visited[v0]=min=++count; /* v0是第count个访问的顶点 */
  for(p=G.vertices[v0].firstarc;p;p=p->nextarc) /* 对v0的每个邻接顶点检查 */
  {
    w=p->adjvex; /* w为v0的邻接顶点 */
    if(visited[w]==0) /* w未曾访问,是v0的孩子 */
    {
      DFSArticul(G,w); /* 返回前求得low[w] */
      if(low[w]<min)
        min=low[w];
      if(low[w]>=visited[v0])
        printf("%d %s\n",v0,G.vertices[v0].data); /* 关节点 */
    }
    else if(visited[w]<min)
      min=visited[w]; /* w已访问,w是v0在生成树上的祖先 */
  }
  low[v0]=min;
}
void FindArticul(ALGraph G)
{ /* 连通图G以邻接表作存储结构,查找并输出G上全部关节点。*/
  /* 全局量count对访问计数。 */
  int i,v;
  ArcNode *p;
  count=1;
  low[0]=visited[0]=1; /* 设定邻接表上0号顶点为生成树的根 */
  for(i=1;i<G.vexnum;++i)
    visited[i]=0; /* 其余顶点尚未访问 */
  p=G.vertices[0].firstarc;
  v=p->adjvex;
  DFSArticul(G,v); /* 从第v顶点出发深度优先查找关节点 */
  if(count<G.vexnum) /* 生成树的根有至少两棵子树 */
  {
    printf("%d %s\n",0,G.vertices[0].data); /* 根是关节点,输出 */
    while(p->nextarc)
    {
      p=p->nextarc;
      v=p->adjvex;
      if(visited[v]==0)
        DFSArticul(G,v);
    }
  }
}
void main()
{
  int i;
  ALGraph g;
  printf("请选择无向图\n");
  CreateGraph(&g);
  printf("输出关节点:\n");
  FindArticul(g);
  printf(" i G.vertices[i].data visited[i] low[i]\n");
  for(i=0;i<g.vexnum;++i)
    printf("%2d %9s %14d %8d\n",i,g.vertices[i].data,visited[i],low[i]);
}

运行结果:

 retrun list 

1.7.7 拓扑排序

#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 5 /* 顶点字符串的最大长度 */
typedef int InfoType;
typedef char VertexType[MAX_NAME]; /* 字符串类型 */
#define MAX_VERTEX_NUM 20
typedef enum{DG,DN,AG,AN}GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct ArcNode
{
  int adjvex; /* 该弧所指向的顶点的位置 */
  struct ArcNode *nextarc; /* 指向下一条弧的指针 */
  InfoType *info; /* 网的权值指针) */
}ArcNode; /* 表结点 */
typedef struct
{
  VertexType data; /* 顶点信息 */
  ArcNode *firstarc; /* 第一个表结点的地址,指向第一条依附该顶点的弧的指针 */
}VNode,AdjList[MAX_VERTEX_NUM]; /* 头结点 */
typedef struct
{
  AdjList vertices;
  int vexnum,arcnum; /* 图的当前顶点数和弧数 */
  int kind; /* 图的种类标志 */
}ALGraph;
int LocateVex(ALGraph G,VertexType u)
{ /* 初始条件: 图G存在,u和G中顶点有相同特征 */
  /* 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
  int i;
  for(i=0;i<G.vexnum;++i)
    if(strcmp(u,G.vertices[i].data)==0)
      return i;
  return -1;
}
Status CreateGraph(ALGraph *G)
{ /* 采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图) */
  int i,j,k;
  int w; /* 权值 */
  VertexType va,vb;
  ArcNode *p;
  printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
  scanf("%d",&(*G).kind);
  printf("请输入图的顶点数,边数: ");
  scanf("%d,%d",&(*G).vexnum,&(*G).arcnum);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
  {
    scanf("%s",(*G).vertices[i].data);
    (*G).vertices[i].firstarc=NULL;
  }
  if((*G).kind==1||(*G).kind==3) /* 网 */
    printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");
  else /* 图 */
    printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");
  for(k=0;k<(*G).arcnum;++k) /* 构造表结点链表 */
  {
    if((*G).kind==1||(*G).kind==3) /* 网 */
      scanf("%d%s%s",&w,va,vb);
    else /* 图 */
      scanf("%s%s",va,vb);
    i=LocateVex(*G,va); /* 弧尾 */
    j=LocateVex(*G,vb); /* 弧头 */
    p=(ArcNode*)malloc(sizeof(ArcNode));
    p->adjvex=j;
    if((*G).kind==1||(*G).kind==3) /* 网 */
    {
      p->info=(int *)malloc(sizeof(int));
      *(p->info)=w;
    }
    else
      p->info=NULL; /* 图 */
    p->nextarc=(*G).vertices[i].firstarc; /* 插在表头 */
    (*G).vertices[i].firstarc=p;
    if((*G).kind>=2) /* 无向图或网,产生第二个表结点 */
    {
      p=(ArcNode*)malloc(sizeof(ArcNode));
      p->adjvex=i;
      if((*G).kind==3) /* 无向网 */
      {
        p->info=(int*)malloc(sizeof(int));
        *(p->info)=w;
      }
      else
        p->info=NULL; /* 无向图 */
      p->nextarc=(*G).vertices[j].firstarc; /* 插在表头 */
      (*G).vertices[j].firstarc=p;
    }
  }
  return OK;
}
VertexType* GetVex(ALGraph G,int v)
{ /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
  if(v>=G.vexnum||v<0)
    exit(ERROR);
  return &G.vertices[v].data;
}
int FirstAdjVex(ALGraph G,VertexType v)
{ /* 初始条件: 图G存在,v是G中某个顶点 */
  /* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
  ArcNode *p;
  int v1;
  v1=LocateVex(G,v); /* v1为顶点v在图G中的序号 */
  p=G.vertices[v1].firstarc;
  if(p)
    return p->adjvex;
  else
    return -1;
}
int NextAdjVex(ALGraph G,VertexType v,VertexType w)
{ /* 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点 */
  /* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。 */
  /*           若w是v的最后一个邻接点,则返回-1 */
  ArcNode *p;
  int v1,w1;
  v1=LocateVex(G,v); /* v1为顶点v在图G中的序号 */
  w1=LocateVex(G,w); /* w1为顶点w在图G中的序号 */
  p=G.vertices[v1].firstarc;
  while(p&&p->adjvex!=w1) /* 指针p不空且所指表结点不是w */
    p=p->nextarc;
  if(!p||!p->nextarc) /* 没找到w或w是最后一个邻接点 */
    return -1;
  else /* p->adjvex==w */
    return p->nextarc->adjvex; /* 返回v的(相对于w的)下一个邻接顶点的序号 */
}
Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
void(*VisitFunc)(char* v); /* 函数变量(全局量) */
void DFS(ALGraph G,int v)
{ /* 从第v个顶点出发递归地深度优先遍历图G。*/
  int w;
  VertexType v1,w1;
  strcpy(v1,*GetVex(G,v));
  visited[v]=TRUE; /* 设置访问标志为TRUE(已访问) */
  VisitFunc(G.vertices[v].data); /* 访问第v个顶点 */
  for(w=FirstAdjVex(G,v1);w>=0;w=NextAdjVex(G,v1,strcpy(w1,*GetVex(G,w))))
    if(!visited[w])
      DFS(G,w); /* 对v的尚未访问的邻接点w递归调用DFS */
}
typedef int QElemType; /* 队列类型 */
typedef struct QNode
{
  QElemType data;
  struct QNode *next;
}QNode,*QueuePtr;

typedef struct
{
  QueuePtr front,rear; /* 队头、队尾指针 */
}LinkQueue;
Status InitQueue(LinkQueue *Q)
{ /* 构造一个空队列Q */
  (*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));
  if(!(*Q).front)
    exit(OVERFLOW);
  (*Q).front->next=NULL;
  return OK;
}
Status QueueEmpty(LinkQueue Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */
  if(Q.front==Q.rear)
    return TRUE;
  else
    return FALSE;
}
Status EnQueue(LinkQueue *Q,QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
  QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
  if(!p) /* 存储分配失败 */
    exit(OVERFLOW);
  p->data=e;
  p->next=NULL;
  (*Q).rear->next=p;
  (*Q).rear=p;
  return OK;
}
Status DeQueue(LinkQueue *Q,QElemType *e)
{ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
  QueuePtr p;
  if((*Q).front==(*Q).rear)
    return ERROR;
  p=(*Q).front->next;
  *e=p->data;
  (*Q).front->next=p->next;
  if((*Q).rear==p)
    (*Q).rear=(*Q).front;
  free(p);
  return OK;
}
void BFSTraverse(ALGraph G,void(*Visit)(char*))
{/*按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。算法7.6 */
  int v,u,w;
  VertexType u1,w1;
  LinkQueue Q;
  for(v=0;v<G.vexnum;++v)
    visited[v]=FALSE; /* 置初值 */
  InitQueue(&Q); /* 置空的辅助队列Q */
  for(v=0;v<G.vexnum;v++) /* 如果是连通图,只v=0就遍历全图 */
    if(!visited[v]) /* v尚未访问 */
    {
      visited[v]=TRUE;
      Visit(G.vertices[v].data);
      EnQueue(&Q,v); /* v入队列 */
      while(!QueueEmpty(Q)) /* 队列不空 */
      {
        DeQueue(&Q,&u); /* 队头元素出队并置为u */
        strcpy(u1,*GetVex(G,u));
        for(w=FirstAdjVex(G,u1);w>=0;w=NextAdjVex(G,u1,strcpy(w1,*GetVex(G,w))))
          if(!visited[w]) /* w为u的尚未访问的邻接顶点 */
          {
            visited[w]=TRUE;
            Visit(G.vertices[w].data);
            EnQueue(&Q,w); /* w入队 */
          }
      }
    }
  printf("\n");
}

void Display(ALGraph G)
{ /* 输出图的邻接矩阵G */
  int i;
  ArcNode *p;
  switch(G.kind)
  {
    case DG: printf("有向图\n");
             break;
    case DN: printf("有向网\n");
             break;
    case AG: printf("无向图\n");
             break;
    case AN: printf("无向网\n");
  }
  printf("%d个顶点:\n",G.vexnum);
  for(i=0;i<G.vexnum;++i)
    printf("%s ",G.vertices[i].data);
  printf("\n%d条弧(边):\n",G.arcnum);
  for(i=0;i<G.vexnum;i++)
  {
    p=G.vertices[i].firstarc;
    while(p)
    {
      if(G.kind<=1) /* 有向 */
      {
        printf("%s→%s ",G.vertices[i].data,G.vertices[p->adjvex].data);
        if(G.kind==DN) /* 网 */
          printf(":%d ",*(p->info));
      }
      else /* 无向(避免输出两次) */
      {
        if(i<p->adjvex)
        {
          printf("%s-%s ",G.vertices[i].data,G.vertices[p->adjvex].data);
          if(G.kind==AN) /* 网 */
            printf(":%d ",*(p->info));
        }
      }
      p=p->nextarc;
    }
    printf("\n");
  }
}
void FindInDegree(ALGraph G,int indegree[])
{ /* 求顶点的入度*/
  int i;
  ArcNode *p;
  for(i=0;i<G.vexnum;i++)
    indegree[i]=0; /* 赋初值 */
  for(i=0;i<G.vexnum;i++)
  {
    p=G.vertices[i].firstarc;
    while(p)
    {
      indegree[p->adjvex]++;
      p=p->nextarc;
    }
  }
}
typedef int SElemType; /* 栈类型 */
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACKINCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack
{
  SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
  SElemType *top; /* 栈顶指针 */
  int stacksize; /* 当前已分配的存储空间,以元素为单位 */
}SqStack; /* 顺序栈 */
Status InitStack(SqStack *S)
{ /* 构造一个空栈S */
  (*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
  if(!(*S).base)
    exit(OVERFLOW); /* 存储分配失败 */
  (*S).top=(*S).base;
  (*S).stacksize=STACK_INIT_SIZE;
  return OK;
}
Status StackEmpty(SqStack S)
{ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
  if(S.top==S.base)
    return TRUE;
  else
    return FALSE;
}
Status Push(SqStack *S,SElemType e)
{ /* 插入元素e为新的栈顶元素 */
  if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */
  {
    (*S).base=(SElemType *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType));
    if(!(*S).base)
      exit(OVERFLOW); /* 存储分配失败 */
    (*S).top=(*S).base+(*S).stacksize;
    (*S).stacksize+=STACKINCREMENT;
  }
  *((*S).top)++=e;
  return OK;
}
Status Pop(SqStack *S,SElemType *e)
{ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
  if((*S).top==(*S).base)
    return ERROR;
  *e=*--(*S).top;
  return OK;
}
Status TopologicalSort(ALGraph G)
{ /* 有向图G采用邻接表存储结构。若G无回路,则输出G的顶点的一个拓扑序列并返回OK, */
  /* 否则返回ERROR。*/
  int i,k,count,indegree[MAX_VERTEX_NUM];
  SqStack S;
  ArcNode *p;
  FindInDegree(G,indegree); /* 对各顶点求入度indegree[0..vernum-1] */
  InitStack(&S); /* 初始化栈 */
  for(i=0;i<G.vexnum;++i) /* 建零入度顶点栈S */
    if(!indegree[i])
      Push(&S,i); /* 入度为0者进栈 */
  count=0; /* 对输出顶点计数 */
  while(!StackEmpty(S))
  { /* 栈不空 */
    Pop(&S,&i);
    printf("%s ",G.vertices[i].data); /* 输出i号顶点并计数 */
    ++count;
    for(p=G.vertices[i].firstarc;p;p=p->nextarc)
    { /* 对i号顶点的每个邻接点的入度减1 */
      k=p->adjvex;
      if(!(--indegree[k])) /* 若入度减为0,则入栈 */
        Push(&S,k);
    }
  }
  if(count<G.vexnum)
  {
    printf("此有向图有回路\n");
    return ERROR;
  }
  else
  {
    printf("为一个拓扑序列。\n");
    return OK;
  }
}
void main()
{
  ALGraph f;
  printf("请选择有向图\n");
  CreateGraph(&f);
  Display(f);
  TopologicalSort(f);
}

运行结果:

 retrun list 

1.7.8 关键路径

#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<math.h> /* floor(),ceil(),abs() */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
/* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define MAX_NAME 5 /* 顶点字符串的最大长度+1 */
typedef int InfoType;
typedef char VertexType[MAX_NAME]; /* 字符串类型 */
/* c7-2.h 图的邻接表存储表示 */
#define MAX_VERTEX_NUM 20
typedef enum{DG,DN,AG,AN}GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct ArcNode
{
  int adjvex; /* 该弧所指向的顶点的位置 */
  struct ArcNode *nextarc; /* 指向下一条弧的指针 */
  InfoType *info; /* 网的权值指针) */
}ArcNode; /* 表结点 */
typedef struct
{
  VertexType data; /* 顶点信息 */
  ArcNode *firstarc; /* 第一个表结点的地址,指向第一条依附该顶点的弧的指针 */
}VNode,AdjList[MAX_VERTEX_NUM]; /* 头结点 */
typedef struct
{
  AdjList vertices;
  int vexnum,arcnum; /* 图的当前顶点数和弧数 */
  int kind; /* 图的种类标志 */
}ALGraph;
int LocateVex(ALGraph G,VertexType u)
{ /* 初始条件: 图G存在,u和G中顶点有相同特征 */
  /* 操作结果: 若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
  int i;
  for(i=0;i<G.vexnum;++i)
    if(strcmp(u,G.vertices[i].data)==0)
      return i;
  return -1;
}
Status CreateGraph(ALGraph *G)
{ /* 采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图) */
  int i,j,k;
  int w; /* 权值 */
  VertexType va,vb;
  ArcNode *p;
  printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
  scanf("%d",&(*G).kind);
  printf("请输入图的顶点数,边数: ");
  scanf("%d,%d",&(*G).vexnum,&(*G).arcnum);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
  {
    scanf("%s",(*G).vertices[i].data);
    (*G).vertices[i].firstarc=NULL;
  }
  if((*G).kind==1||(*G).kind==3) /* 网 */
    printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n");
  else /* 图 */
    printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n");
  for(k=0;k<(*G).arcnum;++k) /* 构造表结点链表 */
  {
    if((*G).kind==1||(*G).kind==3) /* 网 */
      scanf("%d%s%s",&w,va,vb);
    else /* 图 */
      scanf("%s%s",va,vb);
    i=LocateVex(*G,va); /* 弧尾 */
    j=LocateVex(*G,vb); /* 弧头 */
    p=(ArcNode*)malloc(sizeof(ArcNode));
    p->adjvex=j;
    if((*G).kind==1||(*G).kind==3) /* 网 */
    {
      p->info=(int *)malloc(sizeof(int));
      *(p->info)=w;
    }
    else
      p->info=NULL; /* 图 */
    p->nextarc=(*G).vertices[i].firstarc; /* 插在表头 */
    (*G).vertices[i].firstarc=p;
    if((*G).kind>=2) /* 无向图或网,产生第二个表结点 */
    {
      p=(ArcNode*)malloc(sizeof(ArcNode));
      p->adjvex=i;
      if((*G).kind==3) /* 无向网 */
      {
        p->info=(int*)malloc(sizeof(int));
        *(p->info)=w;
      }
      else
        p->info=NULL; /* 无向图 */
      p->nextarc=(*G).vertices[j].firstarc; /* 插在表头 */
      (*G).vertices[j].firstarc=p;
    }
  }
  return OK;
}
VertexType* GetVex(ALGraph G,int v)
{ /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
  if(v>=G.vexnum||v<0)
    exit(ERROR);
  return &G.vertices[v].data;
}
int FirstAdjVex(ALGraph G,VertexType v)
{ /* 初始条件: 图G存在,v是G中某个顶点 */
  /* 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1 */
  ArcNode *p;
  int v1;
  v1=LocateVex(G,v); /* v1为顶点v在图G中的序号 */
  p=G.vertices[v1].firstarc;
  if(p)
    return p->adjvex;
  else
    return -1;
}
int NextAdjVex(ALGraph G,VertexType v,VertexType w)
{ /* 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点 */
  /* 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。 */
  /*           若w是v的最后一个邻接点,则返回-1 */
  ArcNode *p;
  int v1,w1;
  v1=LocateVex(G,v); /* v1为顶点v在图G中的序号 */
  w1=LocateVex(G,w); /* w1为顶点w在图G中的序号 */
  p=G.vertices[v1].firstarc;
  while(p&&p->adjvex!=w1) /* 指针p不空且所指表结点不是w */
    p=p->nextarc;
  if(!p||!p->nextarc) /* 没找到w或w是最后一个邻接点 */
    return -1;
  else /* p->adjvex==w */
    return p->nextarc->adjvex; /* 返回v的(相对于w的)下一个邻接顶点的序号 */
}
Boolean visited[MAX_VERTEX_NUM]; /* 访问标志数组(全局量) */
void(*VisitFunc)(char* v); /* 函数变量(全局量) */
void DFS(ALGraph G,int v)
{ /* 从第v个顶点出发递归地深度优先遍历图G。*/
  int w;
  VertexType v1,w1;
  strcpy(v1,*GetVex(G,v));
  visited[v]=TRUE; /* 设置访问标志为TRUE(已访问) */
  VisitFunc(G.vertices[v].data); /* 访问第v个顶点 */
  for(w=FirstAdjVex(G,v1);w>=0;w=NextAdjVex(G,v1,strcpy(w1,*GetVex(G,w))))
    if(!visited[w])
      DFS(G,w); /* 对v的尚未访问的邻接点w递归调用DFS */
}
void DFSTraverse(ALGraph G,void(*Visit)(char*))
{ /* 对图G作深度优先遍历。*/
  int v;
  VisitFunc=Visit; /* 使用全局变量VisitFunc,使DFS不必设函数指针参数 */
  for(v=0;v<G.vexnum;v++)
    visited[v]=FALSE; /* 访问标志数组初始化 */
  for(v=0;v<G.vexnum;v++)
    if(!visited[v])
      DFS(G,v); /* 对尚未访问的顶点调用DFS */
  printf("\n");
}
typedef int QElemType; /* 队列类型 */
typedef struct QNode
{
  QElemType data;
  struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
  QueuePtr front,rear; /* 队头、队尾指针 */
}LinkQueue;
Status InitQueue(LinkQueue *Q)
{ /* 构造一个空队列Q */
  (*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));
  if(!(*Q).front)
    exit(OVERFLOW);
  (*Q).front->next=NULL;
  return OK;
}
Status QueueEmpty(LinkQueue Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */
  if(Q.front==Q.rear)
    return TRUE;
  else
    return FALSE;
}
Status EnQueue(LinkQueue *Q,QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
  QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
  if(!p) /* 存储分配失败 */
    exit(OVERFLOW);
  p->data=e;
  p->next=NULL;
  (*Q).rear->next=p;
  (*Q).rear=p;
  return OK;
}
Status DeQueue(LinkQueue *Q,QElemType *e)
{ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
  QueuePtr p;
  if((*Q).front==(*Q).rear)
    return ERROR;
  p=(*Q).front->next;
  *e=p->data;
  (*Q).front->next=p->next;
  if((*Q).rear==p)
    (*Q).rear=(*Q).front;
  free(p);
  return OK;
}
void BFSTraverse(ALGraph G,void(*Visit)(char*))
{/*按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。*/
  int v,u,w;
  VertexType u1,w1;
  LinkQueue Q;
  for(v=0;v<G.vexnum;++v)
    visited[v]=FALSE; /* 置初值 */
  InitQueue(&Q); /* 置空的辅助队列Q */
  for(v=0;v<G.vexnum;v++) /* 如果是连通图,只v=0就遍历全图 */
    if(!visited[v]) /* v尚未访问 */
    {
      visited[v]=TRUE;
      Visit(G.vertices[v].data);
      EnQueue(&Q,v); /* v入队列 */
      while(!QueueEmpty(Q)) /* 队列不空 */
      {
        DeQueue(&Q,&u); /* 队头元素出队并置为u */
        strcpy(u1,*GetVex(G,u));
        for(w=FirstAdjVex(G,u1);w>=0;w=NextAdjVex(G,u1,strcpy(w1,*GetVex(G,w))))
          if(!visited[w]) /* w为u的尚未访问的邻接顶点 */
          {
            visited[w]=TRUE;
            Visit(G.vertices[w].data);
            EnQueue(&Q,w); /* w入队 */
          }
      }
    }
  printf("\n");
}
void Display(ALGraph G)
{ /* 输出图的邻接矩阵G */
  int i;
  ArcNode *p;
  switch(G.kind)
  {
    case DG: printf("有向图\n");
             break;
    case DN: printf("有向网\n");
             break;
    case AG: printf("无向图\n");
             break;
    case AN: printf("无向网\n");
  }
  printf("%d个顶点:\n",G.vexnum);
  for(i=0;i<G.vexnum;++i)
    printf("%s ",G.vertices[i].data);
  printf("\n%d条弧(边):\n",G.arcnum);
  for(i=0;i<G.vexnum;i++)
  {
    p=G.vertices[i].firstarc;
    while(p)
    {
      if(G.kind<=1) /* 有向 */
      {
        printf("%s→%s ",G.vertices[i].data,G.vertices[p->adjvex].data);
        if(G.kind==DN) /* 网 */
          printf(":%d ",*(p->info));
      }
      else /* 无向(避免输出两次) */
      {
        if(i<p->adjvex)
        {
          printf("%s-%s ",G.vertices[i].data,G.vertices[p->adjvex].data);
          if(G.kind==AN) /* 网 */
            printf(":%d ",*(p->info));
        }
      }
      p=p->nextarc;
    }
    printf("\n");
  }
}
int ve[MAX_VERTEX_NUM]; 
void FindInDegree(ALGraph G,int indegree[])
{ /* 求顶点的入度*/
  int i;
  ArcNode *p;
  for(i=0;i<G.vexnum;i++)
    indegree[i]=0; /* 赋初值 */
  for(i=0;i<G.vexnum;i++)
  {
    p=G.vertices[i].firstarc;
    while(p)
    {
      indegree[p->adjvex]++;
      p=p->nextarc;
    }
  }
}
typedef int SElemType; /* 栈类型 */
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACKINCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack
{
  SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
  SElemType *top; /* 栈顶指针 */
  int stacksize; /* 当前已分配的存储空间,以元素为单位 */
}SqStack; /* 顺序栈 */
/* bo3-1.c 顺序栈(存储结构由c3-1.h定义)的基本操作(9个) */
Status InitStack(SqStack *S)
{ /* 构造一个空栈S */
  (*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
  if(!(*S).base)
    exit(OVERFLOW); /* 存储分配失败 */
  (*S).top=(*S).base;
  (*S).stacksize=STACK_INIT_SIZE;
  return OK;
}

Status StackEmpty(SqStack S)
{ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
  if(S.top==S.base)
    return TRUE;
  else
    return FALSE;
}

Status Push(SqStack *S,SElemType e)
{ /* 插入元素e为新的栈顶元素 */
  if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */
  {
    (*S).base=(SElemType *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType));
    if(!(*S).base)
      exit(OVERFLOW); /* 存储分配失败 */
    (*S).top=(*S).base+(*S).stacksize;
    (*S).stacksize+=STACKINCREMENT;
  }
  *((*S).top)++=e;
  return OK;
}

Status Pop(SqStack *S,SElemType *e)
{ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
  if((*S).top==(*S).base)
    return ERROR;
  *e=*--(*S).top;
  return OK;
}
Status TopologicalOrder(ALGraph G,SqStack *T)
  /* (全局变量)。T为拓扑序列顶点栈,S为零入度顶点栈。若G无回路,则用栈T */
  /* 返回G的一个拓扑序列,且函数值为OK,否则为ERROR */
  int j,k,count,indegree[MAX_VERTEX_NUM];
  SqStack S;
  ArcNode *p;
  FindInDegree(G,indegree);/*对各顶点求入度indegree[0..vernum-1] */
  InitStack(&S); /* 初始化栈 */
  for(j=0;j<G.vexnum;++j) /* 建零入度顶点栈S */
    if(!indegree[j])
      Push(&S,j); /* 入度为0者进栈 */
  InitStack(T); /* 初始化拓扑序列顶点栈 */
  count=0; /* 对输出顶点计数 */
  for(j=0;j<G.vexnum;++j) /* 初始化ve[]=0 (最小值) */
    ve[j]=0;
  while(!StackEmpty(S))
  { /* 栈不空 */
    Pop(&S,&j);
    Push(T,j); /* j号顶点入T栈并计数 */
    ++count;
    for(p=G.vertices[j].firstarc;p;p=p->nextarc)
    { /* 对j号顶点的每个邻接点的入度减1 */
      k=p->adjvex;
      if(--indegree[k]==0) /* 若入度减为0,则入栈 */
        Push(&S,k);
      if(ve[j]+*(p->info)>ve[k])
        ve[k]=ve[j]+*(p->info);
    }
  }
  if(count<G.vexnum)
  {
    printf("此有向网有回路\n");
    return ERROR;
  }
  else
    return OK;
}
Status CriticalPath(ALGraph G)
  int vl[MAX_VERTEX_NUM];
  SqStack T;
  int i,j,k,ee,el;
  ArcNode *p;
  char dut,tag;
  if(!TopologicalOrder(G,&T)) /* 产生有向环 */
    return ERROR;
  j=ve[0];
  for(i=1;i<G.vexnum;i++) /* j=Max(ve[]) 完成点的值 */
    if(ve[i]>j)
      j=ve[i];
  for(i=0;i<G.vexnum;i++) /* 初始化顶点事件的最迟发生时间(最大值) */
    vl[i]=j; /* 完成点的最早发生时间 */
  while(!StackEmpty(T)) /* 按拓扑逆序求各顶点的vl值 */
    for(Pop(&T,&j),p=G.vertices[j].firstarc;p;p=p->nextarc)
    {
      k=p->adjvex;
      dut=*(p->info); /* dut<j,k> */
      if(vl[k]-dut<vl[j])
        vl[j]=vl[k]-dut;
    }
  printf(" j  k  dut  ee  el  tag\n");
  for(j=0;j<G.vexnum;++j) /* 求ee,el和关键活动 */
    for(p=G.vertices[j].firstarc;p;p=p->nextarc)
    {
      k=p->adjvex;
      dut=*(p->info);
      ee=ve[j];
      el=vl[k]-dut;
      tag=(ee==el)?'*':' ';
      printf("%2d %2d %3d %3d %3d    %c\n",j,k,dut,ee,el,tag); /* 输出关键活动 */
    }
  printf("关键活动为:\n");
  for(j=0;j<G.vexnum;++j) /* 同上 */
    for(p=G.vertices[j].firstarc;p;p=p->nextarc)
    {
      k=p->adjvex;
      dut=*(p->info);
      if(ve[j]==vl[k]-dut)
        printf("%s→%s\n",G.vertices[j].data,G.vertices[k].data); /* 输出关键活动 */
    }
  return OK;
}
void main()
{
  ALGraph h;
  printf("请选择有向网\n");
  CreateGraph(&h);
  Display(h);
  CriticalPath(h);
}

运行结果:

 retrun list 

1.7.9 最短路径

#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
#define MAX_NAME 5 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 20 /* 相关信息字符串的最大长度+1 */
typedef int VRType;
typedef char InfoType;
typedef char VertexType[MAX_NAME];
#define INFINITY INT_MAX /* 用整型最大值代替∞ */
#define MAX_VERTEX_NUM 20 /* 最大顶点个数 */
typedef enum{DG,DN,AG,AN}GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct
{
  VRType adj; /* 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; */
       /* 对带权图,c则为权值类型 */
  InfoType *info; /* 该弧相关信息的指针(可无) */
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct
{
  VertexType vexs[MAX_VERTEX_NUM]; /* 顶点向量 */
  AdjMatrix arcs; /* 邻接矩阵 */
  int vexnum,arcnum; /* 图的当前顶点数和弧数 */
  GraphKind kind; /* 图的种类标志 */
}MGraph;
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];
int LocateVex(MGraph G,VertexType u)
{ /* 初始条件:图G存在,u和G中顶点有相同特征 */
  /* 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
  int i;
  for(i=0;i<G.vexnum;++i)
    if(strcmp(u,G.vexs[i])==0)
      return i;
  return -1;
}
Status CreateDN(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造有向网G */
  int i,j,k,w,IncInfo;
  char s[MAX_INFO],*info;
  VertexType va,vb;
  printf("请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    scanf("%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=INFINITY; /* 网 */
      (*G).arcs[i][j].info=NULL;
    }
  printf("请输入%d条弧的弧尾 弧头 权值(以空格作为间隔): \n",(*G).arcnum);
  for(k=0;k<(*G).arcnum;++k)
  {
    scanf("%s%s%d%*c",va,vb,&w);  /* %*c吃掉回车符 */
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=w; /* 有向网 */
    if(IncInfo)
    {
      printf("请输入该弧的相关信息(<%d个字符): ",MAX_INFO);
      gets(s);
      w=strlen(s);
      if(w)
      {
        info=(char*)malloc((w+1)*sizeof(char));
        strcpy(info,s);
        (*G).arcs[i][j].info=info; /* 有向 */
      }
    }
  }
  (*G).kind=DN;
  return OK;
}
void ShortestPath_DIJ(MGraph G,int v0,PathMatrix *P,ShortPathTable *D)
{ /* 用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及带权长度 */
  /* D[v]。若P[v][w]为TRUE,则w是从v0到v当前求得最短路径上的顶点。 */
  /* final[v]为TRUE当且仅当v∈S*/
  int v,w,i,j,min;
  Status final[MAX_VERTEX_NUM];
  for(v=0;v<G.vexnum;++v)
  {
    final[v]=FALSE;
    (*D)[v]=G.arcs[v0][v].adj;
    for(w=0;w<G.vexnum;++w)
      (*P)[v][w]=FALSE; /* 设空路径 */
    if((*D)[v]<INFINITY)
    {
      (*P)[v][v0]=TRUE;
      (*P)[v][v]=TRUE;
    }
  }
  (*D)[v0]=0;
  final[v0]=TRUE; /* 初始化,v0顶点属于S集 */
  for(i=1;i<G.vexnum;++i) /* 其余G.vexnum-1个顶点 */
  { /* 开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集 */
    min=INFINITY; /* 当前所知离v0顶点的最近距离 */
    for(w=0;w<G.vexnum;++w)
      if(!final[w]) /* w顶点在V-S中 */
 if((*D)[w]<min)
 {
   v=w;
   min=(*D)[w];
 } /* w顶点离v0顶点更近 */
    final[v]=TRUE; /* 离v0顶点最近的v加入S集 */
    for(w=0;w<G.vexnum;++w) /* 更新当前最短路径及距离 */
    {
      if(!final[w]&&min<INFINITY&&G.arcs[v][w].adj<INFINITY&&(min+G.arcs[v][w].adj<(*D)[w]))
      { /* 修改D[w]和P[w],w∈V-S */
        (*D)[w]=min+G.arcs[v][w].adj;
        for(j=0;j<G.vexnum;++j)
          (*P)[w][j]=(*P)[v][j];
        (*P)[w][w]=TRUE;
      }
    }
  }
}
void main()
{
  int i,j,v0=0; /* v0为源点 */
  MGraph g;
  PathMatrix p;
  ShortPathTable d;
  CreateDN(&g);
  ShortestPath_DIJ(g,v0,&p,&d);
  printf("最短路径数组p[i][j]如下:\n");
  for(i=0;i<g.vexnum;++i)
  {
    for(j=0;j<g.vexnum;++j)
      printf("%2d",p[i][j]);
    printf("\n");
  }
  printf("%s到各顶点的最短路径长度为:\n",g.vexs[0]);
  for(i=1;i<g.vexnum;++i)
    printf("%s-%s:%d\n",g.vexs[0],g.vexs[i],d[i]);
}

运行结果:

 retrun list 

1.7.10 每一对顶点之间的最短路径

#define MAX_NAME 5 /* 顶点字符串的最大长度+1 */
#define MAX_INFO 20 /* 相关信息字符串的最大长度+1 */
typedef int VRType;
typedef char VertexType[MAX_NAME];
typedef char InfoType;
#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define INFINITY INT_MAX /* 用整型最大值代替∞ */
#define MAX_VERTEX_NUM 20 /* 最大顶点个数 */
typedef enum{DG,DN,AG,AN}GraphKind; /* {有向图,有向网,无向图,无向网} */
typedef struct
{
  VRType adj; /* 顶点关系类型。对无权图,用1(是)或0(否)表示相邻否; */
       /* 对带权图,c则为权值类型 */
  InfoType *info; /* 该弧相关信息的指针(可无) */
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct
{
  VertexType vexs[MAX_VERTEX_NUM]; /* 顶点向量 */
  AdjMatrix arcs; /* 邻接矩阵 */
  int vexnum,arcnum; /* 图的当前顶点数和弧数 */
  GraphKind kind; /* 图的种类标志 */
}MGraph;
int LocateVex(MGraph G,VertexType u)
{ /* 初始条件:图G存在,u和G中顶点有相同特征 */
  /* 操作结果:若G中存在顶点u,则返回该顶点在图中位置;否则返回-1 */
  int i;
  for(i=0;i<G.vexnum;++i)
    if(strcmp(u,G.vexs[i])==0)
      return i;
  return -1;
}
Status CreateFAG(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,由文件构造没有相关信息的无向图G */
  int i,j,k;
  char filename[13];
  VertexType va,vb;
  FILE *graphlist;
  printf("请输入数据文件名(f7-1.dat):");
  scanf("%s",filename);
  graphlist=fopen(filename,"r");
  fscanf(graphlist,"%d",&(*G).vexnum);
  fscanf(graphlist,"%d",&(*G).arcnum);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    fscanf(graphlist,"%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=0; /* 图 */
      (*G).arcs[i][j].info=NULL; /* 没有相关信息 */
    }
  for(k=0;k<(*G).arcnum;++k)
  {
    fscanf(graphlist,"%s%s",va,vb);
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=(*G).arcs[j][i].adj=1; /* 无向图 */
  }
  fclose(graphlist);
  (*G).kind=AG;
  return OK;
}
Status CreateDG(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造有向图G */
  int i,j,k,l,IncInfo;
  char s[MAX_INFO],*info;
  VertexType va,vb;
  printf("请输入有向图G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    scanf("%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=0; /* 图 */
      (*G).arcs[i][j].info=NULL;
    }
  printf("请输入%d条弧的弧尾 弧头(以空格作为间隔): \n",(*G).arcnum);
  for(k=0;k<(*G).arcnum;++k)
  {
    scanf("%s%s%*c",va,vb);  /* %*c吃掉回车符 */
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=1; /* 有向图 */
    if(IncInfo)
    {
      printf("请输入该弧的相关信息(<%d个字符): ",MAX_INFO);
      gets(s);
      l=strlen(s);
      if(l)
      {
        info=(char*)malloc((l+1)*sizeof(char));
        strcpy(info,s);
        (*G).arcs[i][j].info=info; /* 有向 */
      }
    }
  }
  (*G).kind=DG;
  return OK;
}
Status CreateDN(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造有向网G */
  int i,j,k,w,IncInfo;
  char s[MAX_INFO],*info;
  VertexType va,vb;
  printf("请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    scanf("%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=INFINITY; /* 网 */
      (*G).arcs[i][j].info=NULL;
    }
  printf("请输入%d条弧的弧尾 弧头 权值(以空格作为间隔): \n",(*G).arcnum);
  for(k=0;k<(*G).arcnum;++k)
  {
    scanf("%s%s%d%*c",va,vb,&w);  /* %*c吃掉回车符 */
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=w; /* 有向网 */
    if(IncInfo)
    {
      printf("请输入该弧的相关信息(<%d个字符): ",MAX_INFO);
      gets(s);
      w=strlen(s);
      if(w)
      {
        info=(char*)malloc((w+1)*sizeof(char));
        strcpy(info,s);
        (*G).arcs[i][j].info=info; /* 有向 */
      }
    }
  }
  (*G).kind=DN;
  return OK;
}
Status CreateAG(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造无向图G */
  int i,j,k,l,IncInfo;
  char s[MAX_INFO],*info;
  VertexType va,vb;
  printf("请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    scanf("%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=0; /* 图 */
      (*G).arcs[i][j].info=NULL;
    }
  printf("请输入%d条边的顶点1 顶点2(以空格作为间隔): \n",(*G).arcnum);
  for(k=0;k<(*G).arcnum;++k)
  {
    scanf("%s%s%*c",va,vb); /* %*c吃掉回车符 */
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=(*G).arcs[j][i].adj=1; /* 无向图 */
    if(IncInfo)
    {
      printf("请输入该边的相关信息(<%d个字符): ",MAX_INFO);
      gets(s);
      l=strlen(s);
      if(l)
      {
        info=(char*)malloc((l+1)*sizeof(char));
        strcpy(info,s);
        (*G).arcs[i][j].info=(*G).arcs[j][i].info=info; /* 无向 */
      }
    }
  }
  (*G).kind=AG;
  return OK;
}
Status CreateAN(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造无向网G。算法7.2 */
  int i,j,k,w,IncInfo;
  char s[MAX_INFO],*info;
  VertexType va,vb;
  printf("请输入无向网G的顶点数,边数,边是否含其它信息(是:1,否:0): ");
  scanf("%d,%d,%d",&(*G).vexnum,&(*G).arcnum,&IncInfo);
  printf("请输入%d个顶点的值(<%d个字符):\n",(*G).vexnum,MAX_NAME);
  for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */
    scanf("%s",(*G).vexs[i]);
  for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */
    for(j=0;j<(*G).vexnum;++j)
    {
      (*G).arcs[i][j].adj=INFINITY; /* 网 */
      (*G).arcs[i][j].info=NULL;
    }
  printf("请输入%d条边的顶点1 顶点2 权值(以空格作为间隔): \n",(*G).arcnum);
  for(k=0;k<(*G).arcnum;++k)
  {
    scanf("%s%s%d%*c",va,vb,&w); /* %*c吃掉回车符 */
    i=LocateVex(*G,va);
    j=LocateVex(*G,vb);
    (*G).arcs[i][j].adj=(*G).arcs[j][i].adj=w; /* 无向 */
    if(IncInfo)
    {
      printf("请输入该边的相关信息(<%d个字符): ",MAX_INFO);
      gets(s);
      w=strlen(s);
      if(w)
      {
        info=(char*)malloc((w+1)*sizeof(char));
        strcpy(info,s);
        (*G).arcs[i][j].info=(*G).arcs[j][i].info=info; /* 无向 */
      }
    }
  }
  (*G).kind=AN;
  return OK;
}
Status CreateGraph(MGraph *G)
{ /* 采用数组(邻接矩阵)表示法,构造图G。*/
  printf("请输入图G的类型(有向图:0,有向网:1,无向图:2,无向网:3): ");
  scanf("%d",&(*G).kind);
  switch((*G).kind)
  {
    case DG: return CreateDG(G); /* 构造有向图 */
    case DN: return CreateDN(G); /* 构造有向网 */
    case AG: return CreateAG(G); /* 构造无向图 */
    case AN: return CreateAN(G); /* 构造无向网 */
    default: return ERROR;
  }
}
void DestroyGraph(MGraph *G)
{ /* 初始条件: 图G存在。操作结果: 销毁图G */
  int i,j;
  if((*G).kind<2) /* 有向 */
    for(i=0;i<(*G).vexnum;i++) /* 释放弧的相关信息(如果有的话) */
    {
      for(j=0;j<(*G).vexnum;j++)
        if((*G).arcs[i][j].adj==1&&(*G).kind==0||(*G).arcs[i][j].adj!=INFINITY&&(*G).kind==1) /* 有向图的弧||有向网的弧 */
          if((*G).arcs[i][j].info) /* 有相关信息 */
          {
            free((*G).arcs[i][j].info);
            (*G).arcs[i][j].info=NULL;
          }
    }
  else /* 无向 */
    for(i=0;i<(*G).vexnum;i++) /* 释放边的相关信息(如果有的话) */
      for(j=i+1;j<(*G).vexnum;j++)
        if((*G).arcs[i][j].adj==1&&(*G).kind==2||(*G).arcs[i][j].adj!=INFINITY&&(*G).kind==3) /* 无向图的边||无向网的边 */
          if((*G).arcs[i][j].info) /* 有相关信息 */
          {
            free((*G).arcs[i][j].info);
            (*G).arcs[i][j].info=(*G).arcs[j][i].info=NULL;
          }
  (*G).vexnum=0;
  (*G).arcnum=0;
}
VertexType* GetVex(MGraph G,int v)
{ /* 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值 */
  if(v>=G.vexnum||v<0)
    exit(ERROR);
  return &G.vexs[v];
}
Status PutVex(MGraph *G,VertexType v,VertexType value)
{ /* 初始条件: 图G存在,v是G中某个顶点。操作结果: 对v赋新值value */
  int k;
  k=LocateVex(*G,v); /* k为顶点v在图G中的序号 */
  if(k<0)
    return ERROR;
  strcpy((*G).vexs[k],value);
  return OK;
}
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int DistancMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
void ShortestPath_FLOYD(MGraph G,PathMatrix *P,DistancMatrix *D)
{ /* 用Floyd算法求有向网G中各对顶点v和w之间的最短路径P[v][w]及其 */
  /* 带权长度D[v][w]。若P[v][w][u]为TRUE,则u是从v到w当前求得最短 */
  /* 路径上的顶点。算法7.16 */
  int u,v,w,i;
  for(v=0;v<G.vexnum;v++) /* 各对结点之间初始已知路径及距离 */
    for(w=0;w<G.vexnum;w++)
    {
      (*D)[v][w]=G.arcs[v][w].adj;
      for(u=0;u<G.vexnum;u++)
        (*P)[v][w][u]=FALSE;
      if((*D)[v][w]<INFINITY) /* 从v到w有直接路径 */
      {
        (*P)[v][w][v]=TRUE;
        (*P)[v][w][w]=TRUE;
      }
    }
  for(u=0;u<G.vexnum;u++)
    for(v=0;v<G.vexnum;v++)
      for(w=0;w<G.vexnum;w++)
        if((*D)[v][u]+(*D)[u][w]<(*D)[v][w]) /* 从v经u到w的一条路径更短 */
        {
          (*D)[v][w]=(*D)[v][u]+(*D)[u][w];
          for(i=0;i<G.vexnum;i++)
            (*P)[v][w][i]=(*P)[v][u][i]||(*P)[u][w][i];
        }
}
void main()
{
  MGraph g;
  int i,j,k,l,m,n;
  PathMatrix p;
  DistancMatrix d;
  CreateDN(&g);
  for(i=0;i<g.vexnum;i++)
    g.arcs[i][i].adj=0; /* ShortestPath_FLOYD()要求对角元素值为0 */
  printf("邻接矩阵:\n");
  for(i=0;i<g.vexnum;i++)
  {
    for(j=0;j<g.vexnum;j++)
      printf("%11d",g.arcs[i][j]);
    printf("\n");
  }
  ShortestPath_FLOYD(g,&p,&d);
  printf("d矩阵:\n");
  for(i=0;i<g.vexnum;i++)
  {
    for(j=0;j<g.vexnum;j++)
      printf("%6d",d[i][j]);
    printf("\n");
  }
  for(i=0;i<g.vexnum;i++)
    for(j=0;j<g.vexnum;j++)
      printf("%s到%s的最短距离为%d\n",g.vexs[i],g.vexs[j],d[i][j]);
  printf("p矩阵:\n");
  l=strlen(g.vexs[0]); /* 顶点向量字符串的长度 */
  for(i=0;i<g.vexnum;i++)
  {
    for(j=0;j<g.vexnum;j++)
    {
      if(i!=j)
      {
        m=0; /* 占位空格 */
        for(k=0;k<g.vexnum;k++)
          if(p[i][j][k]==1)
            printf("%s",g.vexs[k]);
          else
            m++;
        for(n=0;n<m*l;n++) /* 输出占位空格 */
          printf(" ");
      }
      else
        for(k=0;k<g.vexnum*l;k++) /* 输出占位空格 */
          printf(" ");
      printf("   "); /* 输出矩阵元素之间的间距 */
    }
    printf("\n");
  }
}

运行结果:

 retrun list 

猜你喜欢

转载自www.cnblogs.com/lx17746071609/p/11855770.html
今日推荐