/* c7-3.h 有向图的十字链表存储表示 */#define MAX_VERTEX_NUM 20typedef 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;elsereturn -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;elsereturn -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);}elsep->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;#include"c3-3.h"#include"bo3-3.c"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");}}

 /* algo7-3.c 实现算法7.10、7.11的程序 */#include"c1.h"#define MAX_NAME 2 /* 顶点字符串的最大长度+1 */typedef int InfoType;typedef char VertexType[MAX_NAME]; /* 字符串类型 */#include"c7-2.h"#include"bo7-2.c"int count; /* 全局量count对访问计数 */int low[MAX_VERTEX_NUM];void DFSArticul(ALGraph G,int v0){ /* 从第v0个顶点出发深度优先遍历图G,查找并输出关节点。算法7.11 */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上全部关节点。算法7.10 *//* 全局量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]);}

 /* main7-3.c 检验bo7-3.c的主程序 */#include"c1.h"typedef char InfoType;#define MAX_Info 80 /* 信息字符串最大长度+1 */#define MAX_VERTEX_NAME 3  /* 顶点字符串最大长度+1 */typedef char  VertexType[MAX_VERTEX_NAME];#include"c7-3.h"#include"bo7-3.c"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);elseInsertArc(&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);}

转载于:https://www.cnblogs.com/cpoint/p/3480214.html

有向图的十字链表存储相关推荐

  1. c语言建立并存储树,利用十字链表存储树结构(便于同时求出某一点的入度与出度)------C语言实现...

    #include #include #include /* 利用十字链表存储有向图,可用于同时查找某个顶点的出度与入度: */ typedef struct edge {//顶点表 int headv ...

  2. 图十字链表并求度c语言,利用十字链表存储树结构(便于同时求出某一点的入度与出度)------C语言实现...

    #include #include #include /* 利用十字链表存储有向图,可用于同时查找某个顶点的出度与入度: */ typedef struct edge{//顶点表 int headve ...

  3. 图的十字链表存储结构

    前面介绍了图的邻接表存储法,本节继续讲解图的另一种链式存储结构--十字链表法. 与邻接表不同,十字链表法仅适用于存储有向图和有向网.不仅如此,十字链表法还改善了邻接表计算图中顶点入度的问题. 十字链表 ...

  4. 图的十字链表存储法详解

    前面介绍了图的邻接表存储法,本节继续讲解图的另一种链式存储结构--十字链表法. 与邻接表不同,十字链表法仅适用于存储有向图和有向网.不仅如此,十字链表法还改善了邻接表计算图中顶点入度的问题. 十字链表 ...

  5. 稀疏矩阵十字链表类java_稀疏矩阵的十字链表存储表示

    typedef struct OLNode{ int  i,j;                 //该非零元的行列下标 ElemType    e; struct  OLNode    *right ...

  6. 5.3稀疏矩阵的十字链表存储

    十字链表产生原因:当矩阵的非零元个数和位置在操作过程中变化较大时,就不宜采用顺序存储结构来表示三元组的线性表. 十字链表特点: 每一个非零元开用含5个域的结点表示,其中i.j和e这3个域分别表示该非零 ...

  7. 稀疏矩阵的十字链表存储表示和实现(第五章 P104 算法5.4)

    稀疏矩阵的十字链表存储 当矩阵的非零元个数和位置在操作过程中变化较大时,就不宜采用顺序存储结构来表示三元组的线性表.对这种类型的矩阵,采用链式存储结构表示三元组的线性表更为恰当. 在链表中,每个非零元 ...

  8. 稀疏矩阵的三元组表与十字链表存储

    三元组表:存储稀疏矩阵的非零元素,以及该元素所在的行.列信息,极大的节省了空间(如相比于一般的二维数组的存储),而且三元组表的某些算法的时间效率也要优于经典算法,如基于三元组表的一次快速转置算法等等 ...

  9. 多重链表 十字链表存储稀疏矩阵,中缀表达式

    第一个term是说该矩阵有4行5列 7个非零元素 为入口 转载于:https://blog.51cto.com/13930723/2362035

最新文章

  1. 主攻ASP.NET.4.5 MVC4.0之重生:Entity Framework生成实体类步骤(十三)
  2. Java架构-(十) 整合spring cloud云架构 - SSO单点登录之OAuth2.0登录认证(1)
  3. linux 查看共享内存最大值,linux上更改共享内存的最大值
  4. 在电路设计中,这7个接口类型太重要了,我难道不该学学么!
  5. 单元测试中Assert类的用法
  6. mysql-聚合函数
  7. [Flex]浅析Mate flex framework在实际项目中的应用(二)
  8. xshell中如何给文件夹加密_Xshell登录服务器的两种认证方式
  9. 7-2 sdut-oop-5 计算长方体和四棱锥的表面积和体积(类的继承) (10 分)
  10. RabbitMQ入门篇、介绍RabbitMQ常用的五种模式
  11. Win10下如何找到下载的主题壁纸,并提取图片
  12. javaweb复习笔记总结
  13. Java多线程——ConcurrentMap、ConcurrentHashMap
  14. SWFObject.js入门
  15. PYTHON 牛客刷题记录
  16. ip地址+斜杠数字含义
  17. Java基础数据类型二进制转换
  18. 解决Unity旋转改变局部坐标问题
  19. Windows邮件服务器hMailServer,网页管理平台WEBADMIN搭建
  20. js微信禁用右上角的分享按钮,,和vue中微信页面禁用右上角的分享按钮的问题

热门文章

  1. 博客主机_自动申请续期免费证书
  2. [转]形态学操作:膨胀与腐蚀
  3. 多数据源报表解析之简单多源报表
  4. 简单分析帆软报表中一次HTTP请求的过程。
  5. apache在线升级yum_基于Redis实现在线游戏积分排行榜 - phyger
  6. php更新不了数据库,为什么我不能使用PHP编辑/更新数据库?
  7. php 复制文件夹并压缩到最小_php实现对文件压缩简单的方法
  8. 调用指定目录下的批处理bat_批处理(.bat)的奇技淫巧
  9. css3网站代码 html5_【实战HTML5与CSS3】用HTML5和CSS3制作页面(上)
  10. pytorch学习笔记(三十九):Fine-Tuning