邻接表存储表示
第七章图状结构

图的应用非常广泛。
2
7.1 图的类型定义
7.2 图的存储表示
7.3 图的遍历
7.4 最小生成树 7.5 两点之间的最短路径问题 7.6 拓扑排序
7.7 关键路径
3
图的结构定义:
图是由一个顶点集 V 和一个弧集 R构 成的数据结构。 Graph = (V , R ) 其中,R={<v,w>| v,w∈V 且 P(v,w)} <v,w>表示从 v 到 w 的一条弧,并称 v 为弧尾,w 为弧头。
4
由于“弧”是有方向的,因此称由顶 点集和弧集构成的图为有向图。
例如: G1 = (V1, VR1)
A
B C D E
其中 V1={A, B, C, D, E} VR1={<A,B>, <A,E>,
<B,C>, <C,D>, <D,B>, <D,A>, <E,C> }
5
若<v, w>VR 且<w, v>VR, 则称 (v,w) 为顶点v 和顶点 w 之间存在一条边。 例如: G2=(V2,VR2) V2={A, B, C, D, E, F} VR2={(A,B), (A,E),
0 0 0 1 0 1
0 0 1 0 0 1
1 1 0 0 0 0
0 1 1 1 0 0
24
无向图邻接矩阵表示法特点:
1)无向图邻接矩阵是对称矩阵 2)顶点v的度 3)判断两顶点v、u是否为邻接点 4)顶点不变,在图中增加、删除边 5)适用于边稠密的图;
25
有向图的邻接矩阵 为非对称矩阵
0 0 0 1 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 0 0
图的邻接矩阵和邻接表相互转换

图的邻接矩阵和邻接表相互转换图的邻接矩阵存储方法具有如下几个特征:1)无向图的邻接矩阵一定是一个对称矩阵。
2)对于无向图的邻接矩阵的第i 行非零元素的个数正好是第i 个顶点的度()i v TD 。
3)对于有向图,邻接矩阵的第i 行非零元素的个数正好是第i 个顶点的出度()i v OD (或入度()i v ID )。
4)用邻接矩阵方法存储图,很容易确定图中任意两个顶点之间是否有边相连;但是,要确定图中有多少条边,则必须按行、按列对每个元素进行检测,所发费得时间代价大。
邻接表是图的一种顺序存储与链式存储相结合的存储方法。
若无向图中有n 个顶点、e 条边,则它的邻接表需n 个头结点和2e 个表结点。
显然,在边稀疏的情况下,用邻接表表示图比邻接矩阵存储空间。
在无向图的邻接表中,顶点i v 的度恰好是第i 个链表中的结点数,而在有向图中,第i 个链表中结点个数是顶点i v 的出度。
在建立邻接表或邻逆接表时,若输入的顶点信息即为顶点的编号,则建立临接表的时间复杂度是)(e n O +;否则,需要通过查找才能得到顶点在图中位置,则时间复杂度为)*(e n O 。
在邻接表上容易找到任意一顶点的第一个邻接点和下一个邻接点,但要判断任意两个顶点之间是否有边或弧,则需要搜索第i 个或第j 个链表,因此,不及邻接矩阵方便。
邻接矩阵和邻接表相互转换程序代码如下:#include<iostream.h>#define MAX 20//图的邻接表存储表示typedef struct ArcNode{int adjvex; //弧的邻接定点 char info; //邻接点值struct ArcNode *nextarc; //指向下一条弧的指针}ArcNode;typedef struct Vnode{ //节点信息char data;ArcNode *link;}Vnode,AdjList[MAX];typedef struct{AdjList vertices;int vexnum; //节点数int arcnum; //边数}ALGraph;//图的邻接矩阵存储表示typedef struct{int n; //顶点个数char vexs[MAX]; //定点信息int arcs[MAX][MAX]; //边信息矩阵}AdjMatrix;/***_____________________________________________________***///函数名:AdjListToMatrix(AdjList g1,AdjListMatrix &gm,int n)//参数:(传入)AdjList g1图的邻接表,(传入)int n顶点个数,(传出)AdjMatrix gm图的邻接矩阵//功能:把图的邻接表表示转换成图的邻接矩阵表示void AdjListToAdjMatrix(ALGraph gl,AdjMatrix &gm){int i,j,k;ArcNode *p;gm.n=gl.vexnum;for(k=0;k<gl.vexnum;k++)gm.vexs[k]=gl.vertices[k].data;for(i=0;i<MAX;i++)for(j=0;j<MAX;j++)gm.arcs[i][j]=0;for(i=0;i<gl.vexnum;i++){p=gl.vertices[i].link; //取第一个邻接顶点while(p!=NULL){ //取下一个邻接顶点gm.arcs[i][p->adjvex]=1;p=p->nextarc;}}}/***________________________________________________***///函数名:AdjMatrixToAdjListvoid AdjMatrixToAdjList(AdjMatrix gm,ALGraph &gl){int i,j,k,choice;ArcNode *p;k=0;gl.vexnum=gm.n;cout<<"请选择所建立的图形是无向图或是有向图:";cin>>choice;for(i=0;i<gm.n;i++){gl.vertices[i].data=gm.vexs[i];gl.vertices[i].link=NULL;}for(i=0;i<gm.n;i++)for(j=0;j<gm.n;j++)if(gm.arcs[i][j]==1){k++;p=new ArcNode;p->adjvex=j;p->info=gm.vexs[j];p->nextarc=gl.vertices[i].link;gl.vertices[i].link=p;}if(choice==1)k=k/2;gl.arcnum=k;}void CreateAdjList(ALGraph &G){int i,s,d,choice;ArcNode *p;cout<<"请选择所建立的图形是有向图或是无向图:";cin>>choice;cout<<"请输入节点数和边数:"<<endl;cin>>G.vexnum>>G.arcnum;for(i=0;i<G.vexnum;i++){cout<<"第"<<i<<"个节点的信息:";cin>>G.vertices[i].data;G.vertices[i].link=NULL;}if(choice==1){for(i=0;i<2*(G.vexnum);i++){cout<<"边----起点序号,终点序号:";cin>>s>>d;p=new ArcNode;p->adjvex=d;p->info=G.vertices[d].data;p->nextarc=G.vertices[s].link;G.vertices[s].link=p;}}else{for(i=0;i<G.vexnum;i++){cout<<"边----起点序号,终点序号:";cin>>s>>d;p=new ArcNode;p->adjvex=d;p->info=G.vertices[d].data;p->nextarc=G.vertices[s].link;G.vertices[s].link=p;}}}void CreateAdjMatrix(AdjMatrix &M){int i,j,k,choice;cout<<"请输入顶点个数:";cin>>M.n;cout<<"请输入如顶点信息:"<<endl;for(k=0;k<M.n;k++)cin>>M.vexs[k];cout<<"请选择所建立的图形是无向图或是有向图:";cin>>choice;cout<<"请输入边信息:"<<endl;for(i=0;i<M.n;i++)for(j=0;j<M.n;j++)M.arcs[i][j]=0;switch(choice){case 1:{for(k=0;k<M.n;k++){cin>>i>>j;M.arcs[i][j]=M.arcs[j][i]=1;}};break;case 2:{for(k=0;k<M.n;k++){cin>>i>>j;M.arcs[i][j]=1;}};break;}}void OutPutAdjList(ALGraph &G){int i;ArcNode *p;cout<<"图的邻接表如下:"<<endl;for(i=0;i<G.vexnum;i++){cout<<G.vertices[i].data;p=G.vertices[i].link;while(p!=NULL){cout<<"---->("<<p->adjvex<<" "<<p->info<<")";p=p->nextarc;}cout<<endl;}}void OutPutAdjMatrix(AdjMatrix gm){cout<<"图的邻接矩阵如下:"<<endl;for(int i=0;i<gm.n;i++){。
数据结构-邻接表

delete [ ] visited; }
8.4 图的遍历(续)
图的生成树
定义:G的所有顶点加上遍历过程中经过的边 所构成的子图称作图G的生成树G’
visited[v]=1;
/*标记第v个顶点已访问*/
/*访问第v个顶点邻接的未被访问过的顶点w,并从w出发递归地按照深度 优先的方式进行遍历*/
w= GetFirstNeighbor (v); /*得到第v个顶点的第一个邻接顶点w*/
while(w!= -1)
{ if(!visited[w]) DepthFirstSearch(w,visited,Visit); //递归调用
void BroadFirstSearch(const int v, int visited[ ], void visit(VT Vertex));
public:
AdjTWGraph(void);
~AdjTWGraph(void);
int NumOfVertices(void)const;
int NumOfEdges(void)const;
(2) 无向图:第i个链表中的表结点数为TD(vi); 能逆求邻有I接向D表(图vi。):。第为i个便链于表求中ID的(v表i) 可结另点外数建为立OD有(v向i),图不的
(3) 容易寻找顶点的邻接 点,但判断两顶点间是 否有边或弧,需搜索两 结点对应的单链表。
(4) 邻接表多用于稀疏 图的存储(e<<n2)
void Visit(VT item))
邻接表表示法的特点

邻接表表示法的特点
邻接表表示法是一种把图结构的存储结构。
它的空间使用效率高,操作效率也比较高,而且相对来说存储结构比较清楚方便管理。
首先,邻接表存储结构最大的优点就是空间复杂度极小,因为它只需要存储图中的顶点信息和边信息就可以描述图中的结构,此外,每个顶点只需要存储其相邻节点的序号而不需要存储两顶点之间的
距离,所以节点所占的内存空间少,也减少了图中属性的存储。
其次,邻接表存储结构的操作效率也比较高,因为在邻接表存储结构中,每个顶点都有相应的链表来存储其相邻节点的序号,所以在查找和更新操作中,只需要找到顶点的链表,就可以很方便地查找或更新其邻接节点的信息,也十分提高了操作效率。
此外,邻接表存储结构的结构也比较清晰,在建立时只需要用一个数据结构把图的顶点和邻接边按照一定的顺序存储起来,就可以把图中的结构信息全部存储起来。
这样,程序员就可以非常快速地定位顶点的相邻边,也方便管理。
总之,邻接表表示法优化了图的存储,使得程序员可以更加快速准确地定位顶点的相邻边,并且使得管理变得更加简单方便。
邻接表表示法也在图的可视化中有着广泛的应用,有助于更好地提高图的存储效率和操作效率。
因此,邻接表表示法的特点是空间使用效率高,操作效率也比较高,相对来说存储结构比较清晰方便管理,且有着广泛的应用。
未来,会有更多的算法和应用技术来提高图的效率,并且在使用邻接表表示
法时,还有很多细节需要更新和思考,以更加优雅地描述图结构。
实验六 图及其应用

实验六图及其应用数据结构实验六图及其应用1、实验目的? 熟练掌握图的两种存储结构(邻接矩阵和邻接表)的表示方法 ? 掌握图的基本运算及应用? 加深对图的理解,逐步培养解决实际问题的编程能力2、实验内容:采用邻接表或邻接矩阵方式存储图,实现图的深度遍历和广度遍历;用广度优先搜索方法找出从一顶点到另一顶点边数最少的路径。
1.问题描述:利用邻接表存储结构,设计一种图(有向或无向),并能够对其进行如下操作:1) 创建一个可以随机确定结点数和弧(有向或无向)数的图; 2) 根据图结点的序号,得到该结点的值;3) 根据图结点的位置的第一个邻接顶点的序号,以及下一个邻接顶点的序号;4) 实现从第v 个顶点出发对图进行深度优先递归遍历; 5) 实现对图作深度优先遍历;6) 实现对图进行广度优先非递归遍历; 编写主程序,实现对各不同的算法调用。
2.实现要求:(以邻接表存储形式为例)编写图的基本操作函数::对图的各项操作一定要编写成为C(C++)语言函数,组合成模块化的形式,每个算法的实现要从时间复杂度和空间复杂度上进行评价。
1)“建立图的邻接表算法”:CreateGraph(ALGraph *G) 操作结果:采用邻接表存储结构,构造没有相关信息的图G2)“邻接表表示的图的递归深度优先遍历算法”:DFSTraverse(ALGraphG,void(*Visit)(char*)) 初始条件:图G 已经存在;操作结果:返回图的按深度遍历的结果。
3)“邻接表表示的图的广度优先遍历算法”: BFSTraverse(ALGraphG,void(*Visit)(char*)) 初始条件:图G 已经存在;操作结果:返回图的按广度遍历的结果。
4)“邻接表从某个结点开始的广度优先遍历算法”:BFS(ALGraph G, int v)初始条件:图G 已经存在;操作结果:返回图从某个结点开始的按广度遍历的结果。
分析: 修改输入数据,预期输出并验证输出的结果,加深对有关算法的理解。
数据结构-图及其存储结构

for (j=0;j<G.vexnum;+ +j ) adj Info G.arcs[i][j]={∞,NULL}; //Arccell的形式为: for (k=0;k<G.arcnum;+ +i ) { //二维数组存放各边上的信息 scanf(v1,v2,w); i=locatevex(G,v1); j=locatevex(G,v2); //求顶点v1,v2在图中的位置 G.arcs[i][j].adj=w; G.arcs[j][i].adj=w; //无向网的邻接矩阵是对称的 if (IncInfo) Input (*G.arcs[i][j].info); //将弧上的信息存储在指针info
case UDN: return CreateUDN(G);
default : return ERROR; }//CreateGraph
二、存储结构
2.数组表示法前提下图的输入
*以无向网为例,即当用户输入图的类型标志为UDN时,有:
Status CreateUDN(MGraph &G){ scanf(G.vexnum,G.arcnum,IncInfo); //IncInfo 为0时表示各弧
v2 6 5
v1 5 1 5 v3 3 6 4 2 v4
一个连通无向图的生成树是该图的一个连通分量,它 包含有该图的所有n个顶点以及连接这n个顶点的(n-1) 条边。 边或弧上带权值的图称为带权图或网(分为无向网和 有向网)。 一个无向图的所有生成树中,边上的权值之和最小的 生成树称为该图的最小生成树或最小代价生成树。
数据结构与算法教学大纲

《数据结构与算法》课程教学大纲一、《数据结构》课程说明(一)课程代码:(二)课程英文名称:Data Stucture(三)开课对象:电子专业的本科生(四)课程性质:专业基础课《数据结构》是计算机专业的技术基础课。
主要讲述算法设计和数据结构的基础原理和技术。
是计算机科学与技术专业的核心课程。
由于本课程是计算机程序设计理论基础,所以也是非计算机理工类专业的重要选修课程。
本课程的学习过程也是算法设计的技巧和能力的训练过程。
本课程的先导课程为《C语言》,《计算机基础》。
(五)教学目的:通过本课程的学习,使学生深透地理解数据结构的逻辑结构和物理结构的基本概念以及有关算法,培养基本的、良好的程序设计技能,编制高效可靠的程序,为学习《操作系统》、《编译原理》和《数据库》等课程奠定基础。
(六)教学内容:本课程主要包括绪论、线性表、树型结构、图、查找、排序等几个部分。
通过教学的各个环节使学生达到各章中所提的基本要求。
习题课是重要的教学环节,教师必须予以重视。
(七)学时数、学分数及学时数具体分配学时数: 68学时学分数: 4学分(八)教学方式以多媒体教学手段为主要形式的课堂教学。
(九)考核方式和成绩记载说明考核方式为考试。
严格考核学生出勤情况,达到学籍管理规定的旷课量取消考试资格。
综合成绩根据平时成绩和期末成绩评定,平时成绩占20% ,期末成绩占80% 。
二、讲授大纲与各章的基本要求第一章绪论教学要点:通过本章的教学使学生初步了解《数据结构》的内容和目的,掌握数据结构的概念以及分类、抽象数据类型的表示与实现、算法的概念、算法的特性、算法的目标、算法效率的度量、算法的存储空间需求。
1、使学生准确掌握数据结构的概念。
2、使学生领会抽象数据类型的表示与实现。
3、使学生充分理解算法的概念。
4、明确算法的特性。
5、明确算法的目标。
6、熟练地掌握算法效率的度量。
7、掌握算法的存储空间需求。
教学时数:4学时教学内容:第一节数据结构概述第二节数据结构的概念一、基本概念二、数据结构及分类三、数据结构课程的内容第三节数据类型和抽象数据类型一、数据类型二、抽象数据类型第四节算法和算法分析考核要求:1、数据结构概述(识记)2、数据结构的概念2.1基本概念(识记)2.2数据结构及分类(识记)2.3数据结构课程的内容(识记)3、数据类型和抽象数据类型3.1数据类型(领会)3.2抽象数据类型(领会)4、算法和算法分析(应用)第二章线性表教学要点:通过本章的教学使学生初步了解线性表的结构特点;掌握顺序的和链式的存储结构各自特色;熟练掌握线性表的操作,以及链表的指针运算和各种链表的操作;理解循环链表以及双向链表。
图的定义和基本术语图的存储结构图的遍历生成树最短路径

DeleteVex(&G, v) //删除顶点 初始条件: 图G存在, v和G中顶点有相同特性 。 操作结果:删除G中顶点v及其相关的弧。
InsertArc(&G, v, w) //插入弧 初始条件:图G存在,v 和w是G中两个顶点。 操作结果:在G中增添弧<v,w>,若G是无向的, 则还增添对称弧<w,v>。
DestroyGraph (&G ) // 销毁 初始条件:图G存在。 操作结果:销毁图G 。
LocateVex(G, u) // 定位 初始条件:图G存在,u 和G中顶点有相同特性 。 操作结果: 若G中存在顶点u ,则返回该顶点在 图中位置 ;否则返回其它信息。
GetVex(G, v)// 求值 初始条件:图G存在,v 是G中某个顶点。 操作结果:返回v的值。
//{有向图,有向网,无向图,无向网}
typedef struct ArcCell {// 弧的定义 VRType adj;//VRType是顶点关系类型。对无权图,
//用1或0表示相邻否;对带权图,则为权值类型。 InfoType *info; // 该弧相关信息的指针 } ArcCell ,
AdjMatrix[MAX_VERTEX_NUM] [MAX_VERTEX_NUM];
V2
V3
0110 0000 0001 10 0 0
//- -图的数组(邻接矩阵)存储表示--
#define INFINITY INT_MAX //最大值∞ #define MAX_VERTEX_NUM 20//最大顶点个数 typedef enum{DG,DN,UDG, UDN }graphkind;
表示,称为无向边;
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
邻接表存储表示Status Build_AdjList(ALGraph &G)//输入有向图的顶点数,边数,顶点信息和边的信息建立邻接表{InitALGraph(G);scanf("%d",&v);if(v<0) return ERROR;G.vexnum=v;scanf("%d",&a);if(a<0) return ERROR;G.arcnum=a;for(m=0;m<v;m++)G.vertices[m].data=getchar();for(m=1;m<=a;m++){t=getchar();h=getchar();if((i=LocateVex(G,t))<0) return ERROR;if((j=LocateVex(G,h))<0) return ERROR;p=(ArcNode*)malloc(sizeof(ArcNode));if(!G.vertices.[i].firstarc) G.vertices[i].firstarc=p;else{for(q=G.vertices[i].firstarc;q->nextarc;q=q->nextarc);q->nextarc=p;}p->adjvex=j;p->nextarc=NULL;}//whilereturn OK;}//Build_AdjList邻接多重表存储表示Status Build_AdjMulist(AMLGraph &G)//输入有向图的顶点数,边数,顶点信息和边的信息建立邻接多重表{InitAMLGraph(G);scanf("%d",&v);if(v<0) return ERROR; //顶点数不能为负G.vexnum=v;scanf(%d",&a);if(a<0) return ERROR; //边数不能为负G.arcnum=a;for(m=0;m<v;m++)G.adjmulist[m].data=getchar(); //输入各顶点的符号for(m=1;m<=a;m++){t=getchar();h=getchar(); //t为弧尾,h为弧头if((i=LocateVex(G,t))<0) return ERROR;if((j=LocateVex(G,h))<0) return ERROR; //顶点未找到p=(EBox*)malloc(sizeof(EBox));p->ivex=i;p->jvex=j;p->ilink=NULL;p->jlink=NULL; //边结点赋初值if(!G.adjmulist[i].firstedge) G.adjmulist[i].firstedge=p; else{q=G.adjmulist[i].firstedge;while(q){r=q;if(q->ivex==i) q=q->ilink;else q=q->jlink;}if(r->ivex==i) r->ilink=p;//else r->jlink=p; //}//elseif(!G.adjmulist[j].firstedge) G.adjmulist[j].firstedge=p; else{q=G.adjmulist[i].firstedge;while(q){r=q;if(q->jvex==j) q=q->jlink;else q=q->ilnk;}if(r->jvex==j) r->jlink=p;else r->ilink=p;}//else}//forreturn OK;}//Build_AdjList图的邻接表存储的15个基本操作int LocateVex(ALGraph G,VertexType u){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){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;}elsep->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;}elsep->info=NULL;p->nextarc=(*G).vertices[j].firstarc;(*G).vertices[j].firstarc=p;}}return OK;}void DestroyGraph(ALGraph *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;elsereturn -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=p->nextarc;if(!p||!p->nextarc)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;}elsep->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;}elsep->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指向下一条弧*/q=p;p=p->nextarc;}if(p&&p->adjvex==j){if(p==(*G).vertices[i].firstarc) /(*G).vertices[i].firstarc=p->nextarc; /* 指向下一条弧*/ elseq->nextarc=p->nextarc;if((*G).kind%2)free(p->info);free(p);(*G).arcnum--;}if((*G).kind>=2){p=(*G).vertices[j].firstarc;while(p&&p->adjvex!=i){ /* p指向下一条弧*/q=p;p=p->nextarc;}if(p&&p->adjvex==i){if(p==(*G).vertices[j].firstarc)(*G).vertices[j].firstarc=p->nextarc;elseq->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){int w;VertexType v1,w1;strcpy(v1,*GetVex(G,v));visited[v]=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);}非递归深度优先遍历void DFSTraverse(ALGraph G,void(*Visit)(char*)){int v;VisitFunc=Visit;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;void BFSTraverse(ALGraph G,void(*Visit)(char*))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++)if(!visited[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]){visited[w]=TRUE;Visit(G.vertices[w].data);EnQueue(&Q,w); /* w入队*/}}}printf("\n");}邻接矩阵void Display(ALGraph 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");}}。