数据结构中图的全部操作
数据结构中的图的遍历算法

数据结构中的图的遍历算法图是一种非常重要且广泛应用的数据结构,它由顶点和边组成,可以用来表示各种实际问题,如社交网络、路线规划等。
图的遍历算法是对图中的所有顶点进行系统访问的方法,它可以用来查找、遍历和搜索图中的元素。
本文将介绍图的遍历算法的基本概念和常用的实现方法。
一、图的遍历算法概述图的遍历算法是指按照某种规则遍历图中的所有顶点,以便于查找、遍历和搜索图中的元素。
常用的图的遍历算法有深度优先搜索(DFS)和广度优先搜索(BFS)两种。
深度优先搜索(DFS)是一种先访问顶点的所有邻接顶点,再递归访问邻接顶点的邻接顶点的算法。
它以深度为优先级,一直向前走到不能继续为止,然后返回到前一个结点,继续向前走,直到遍历完整个图。
广度优先搜索(BFS)是一种先访问顶点的所有邻接顶点,再访问邻接顶点的邻接顶点,以此类推的算法。
它以广度为优先级,先访问离起始顶点最近的顶点,然后依次访问离起始顶点更远的顶点,直到遍历完整个图。
二、深度优先搜索(DFS)深度优先搜索是一种递归的搜索算法,它的基本思想是从图的某个顶点出发,沿着一条路径一直深入直到不能继续为止,然后返回到前一个结点,继续向前走。
具体实现时,可以使用递归或栈来保存需要访问的顶点。
以下是深度优先搜索的基本步骤:1. 选择一个起始顶点作为当前顶点,将其标记为已访问。
2. 访问当前顶点,并将其加入遍历结果。
3. 从当前顶点的未访问邻接顶点中选择一个作为下一个当前顶点,重复步骤2。
4. 如果当前顶点的所有邻接顶点都已访问,则返回到前一个顶点,重复步骤3。
5. 重复步骤4,直到遍历完整个图。
三、广度优先搜索(BFS)广度优先搜索是一种迭代的搜索算法,它的基本思想是从图的某个顶点出发,依次访问其所有未访问过的邻接顶点,然后再依次访问这些邻接顶点的未访问过的邻接顶点,直到遍历完整个图。
具体实现时,可以使用队列来保存需要访问的顶点。
以下是广度优先搜索的基本步骤:1. 选择一个起始顶点作为当前顶点,将其标记为已访问,并将其加入遍历结果。
图的定义和基本操作

图的定义和基本操作
一、图的定义 二、图的基本术语 三、图的基本操作
一、图的定义
图(Graph)是由顶点的有限集合和描述顶点关系的有限集合组成的。
G=(V, R)
V是图G中顶点的有限
V={v0, v1, v2, …, vn}
ห้องสมุดไป่ตู้
集合,称为顶点集
R={VR}
VR={<vi, vj> | vi, vj∈V且P(vi, vj)}
⑧ InsertVex (G, v):图G存在,在G中增加一个新顶点v。 ⑨ DeleteVex (G, v):图G存在,v是G中某个顶点,删除顶点v及其相关 联的弧。 ⑩ InsertArc (G, v, w):图G存在,v和w是G中两个顶点,在G中增加一条 从顶点v到顶点w的弧或边。 ⑪ DeleteArc (G, v, w):图G存在,v和w是G中两个顶点,删除G中从顶 点v到顶点w的弧或边。
⑫ DFSTraverse (G):图G存在,对G进行深度优先遍历。
⑬ BFSTraverse (G):图G存在,对G进行广度优先遍历。
数据结构
生成树
三、图的基本操作
① CreateGraph (G):构造图G。 ② DestoryGraph (G):图G存在,销毁图G。 ③ LocateVex (G, v):图G存在,若图G中存在顶点v,则返回顶点v在图 中的位置;否则返回0。 ④ GetVex (G, v):图G存在,v是G中某个顶点,返回v的值。 ⑤ PutVex (G, v, value):图G存在,v是G中某个顶点,将value值赋给v。 ⑥ FirstAdjVex (G, v):图G存在,v是G中某个顶点,返回v的第一个邻接 点;若v无邻接点,则返回空。 ⑦ NextAdjVex (G, v, w):图G存在,v是G中某个顶点,w是v的邻接顶点, 返回v的(相对于w的)下一个邻接顶点;若w是v的最后一个邻接顶点, 则返回空。
图的基本操作 实验报告

图的基本操作实验报告图的基本操作实验报告引言:图是一种常见的数据结构,广泛应用于计算机科学和其他领域。
本实验报告旨在介绍图的基本操作,包括创建图、添加节点和边、遍历图等,并通过实验验证这些操作的正确性和效率。
实验目的:1. 了解图的基本概念和术语;2. 掌握图的创建和修改操作;3. 熟悉图的遍历算法;4. 分析图的操作的时间复杂度。
实验过程:1. 创建图首先,我们需要创建一个图对象。
图可以用邻接矩阵或邻接表来表示。
在本实验中,我们选择使用邻接表来表示图。
通过遍历输入的节点和边信息,我们可以创建一个包含所有节点和边的图。
2. 添加节点和边在创建图对象后,我们可以通过添加节点和边来构建图的结构。
通过输入节点的标识符和边的起始和结束节点,我们可以在图中添加新的节点和边。
添加节点和边的操作可以通过修改邻接表来实现,将节点和边的信息存储在对应的链表中。
3. 遍历图遍历图是图操作中常用的操作之一。
通过遍历图,我们可以访问图中的所有节点和边。
在本实验中,我们选择使用深度优先搜索(DFS)算法来遍历图。
DFS算法通过递归的方式遍历图中的节点,先访问当前节点,然后再递归地访问与当前节点相邻的节点。
4. 分析时间复杂度在实验过程中,我们记录了图的操作所花费的时间,并分析了它们的时间复杂度。
通过对比不同规模的图的操作时间,我们可以评估图操作的效率和可扩展性。
实验结果:通过实验,我们成功创建了一个图对象,并添加了多个节点和边。
我们还通过DFS算法遍历了图,并记录了遍历的顺序。
实验结果表明,我们的图操作实现正确,并且在不同规模的图上都能够高效地工作。
讨论与结论:本实验报告介绍了图的基本操作,并通过实验验证了这些操作的正确性和效率。
通过实验,我们了解到图是一种重要的数据结构,可以用于解决许多实际问题。
同时,我们还深入分析了图操作的时间复杂度,为后续的图算法设计和优化提供了参考。
总结:通过本次实验,我们对图的基本操作有了更深入的了解。
数据结构主要研究内容

数据结构主要研究内容数据结构是计算机科学中的一门基础课程,主要研究各种数据组织方式和数据操作算法。
它是计算机科学和技术领域的基础,对于编写高效的程序和解决实际问题具有重要的意义。
本文将介绍数据结构的主要研究内容,包括线性表、栈、队列、树、图等。
一、线性表线性表是数据结构中最基本的一种形式,它将一组数据元素按照线性顺序排列。
线性表的常见实现方式有顺序表和链表。
顺序表使用数组等连续的存储空间存储数据,而链表使用链式存储结构,通过节点之间的指针链接起来。
线性表的常见操作包括插入、删除、查找等。
二、栈栈是一种特殊的线性表,它的插入和删除操作只能在同一端进行,即“先入后出”。
栈的常见操作包括入栈和出栈。
入栈将元素放入栈顶,出栈将栈顶元素取出。
栈的应用非常广泛,例如函数调用栈、表达式求值等。
三、队列队列也是一种特殊的线性表,它的插入操作只能在队尾进行,删除操作只能在队首进行,即“先入先出”。
队列的应用场景包括多线程任务调度、模拟系统等。
队列的常见操作包括入队和出队。
四、树树是一种非线性的数据结构,由节点和节点之间的连接组成。
树的每个节点可以有零个或多个子节点。
树的应用非常广泛,包括文件系统、数据库索引等。
树的常见类型有二叉树、平衡树、红黑树等,每种类型都有相应的操作和算法。
五、图图是一种复杂的非线性数据结构,由节点和节点之间的边组成。
图的节点称为顶点,边表示两个顶点之间的关系。
图的应用包括社交网络分析、路径规划等。
图的常见操作包括遍历、最短路径算法等。
六、其他数据结构除了上述介绍的主要数据结构外,还有许多其他重要的数据结构,比如堆、散列表、图的邻接矩阵等。
每种数据结构都有自己的特点和应用场景,能够帮助解决各种不同类型的问题。
综上所述,数据结构主要研究包括线性表、栈、队列、树、图等各种数据组织方式和操作算法。
这些数据结构是计算机科学和技术领域中的基础,对于编写高效的程序和解决实际问题具有重要的意义。
熟练掌握各种数据结构的特点和应用能够帮助我们更好地进行程序设计和算法分析。
图的基本操作与应用

图的基本操作与应用图是一种重要的数据结构,广泛应用于计算机科学和相关领域。
本文将介绍图的基本操作和常见的应用场景,通过详细讲解来帮助读者更好地理解和应用图。
一、图的定义和表示图是由节点(顶点)和边组成的集合。
节点表示实体,边表示节点之间的关系。
图可以用以下方式进行表示:邻接矩阵和邻接表。
1. 邻接矩阵:用二维数组表示图的连接关系,其中数组元素a[i][j]表示节点i到节点j是否存在一条边。
2. 邻接表:使用链表或数组的方式表示节点的连接关系。
每个节点对应一个链表,链表中存储与该节点相连接的其他节点。
二、图的基本操作1. 添加节点:图中可以通过添加节点来增加实体。
添加节点时,需要更新相应的连接关系,即在邻接矩阵或邻接表中添加对应的行或节点。
2. 添加边:向图中添加边可以表示节点之间的关系。
在邻接矩阵中,将对应的元素设置为1。
在邻接表中,将对应的节点添加到该节点的链表中。
3. 删除节点:从图中删除节点时,需要将与该节点相关的边一并删除。
删除节点后,对应的行或链表也需要进行相应的调整。
4. 删除边:删除边可以断开节点之间的关系。
在邻接矩阵中,将对应的元素设置为0。
在邻接表中,删除对应的节点。
三、图的应用场景1. 社交网络分析:图可以用于分析社交网络中的关系,如朋友关系、粉丝关系等。
可以通过图的遍历算法,寻找潜在的朋友或影响力人物。
2. 路径规划:图可以表示地理空间中的路径,如导航系统中的道路网络。
可以使用图的最短路径算法,如Dijkstra算法或A*算法,来计算最优路径。
3. 组织架构图:图可以用于表示组织或公司的架构,帮助人们更好地理解不同部门之间的关系和沟通路径。
4. 网络流量分析:图可以用于分析网络中的流量,如网络路由、数据传输等。
可以通过图的最大流算法,如Ford-Fulkerson算法,来优化网络流量分配和传输效率。
5. 数据库关系图:图可以用于表示数据库中的关系表,帮助人们理解和查询表之间的关系,如主外键关系等。
第7章图_数据结构

v4
11
2013-8-7
图的概念(3)
子图——如果图G(V,E)和图G’(V’,E’),满足:V’V,E’E 则称G’为G的子图
2 1 4 3 5 6 3 5 6 1 2
v1 v2 v4 v3 v2
v1 v3 v4
v3
2013-8-7
12
图的概念(4)
路径——是顶点的序列V={Vp,Vi1,……Vin,Vq},满足(Vp,Vi1),
2013-8-7 5
本章目录
7.1 图的定义和术语 7.2 图的存储结构
7.2.1 数组表示法 7.2.2 邻接表 ( *7.2.3 十字链表 7.3.1 深度优先搜索 7.3.2 广度优先搜索 7.4.1 图的连通分量和生成树 7.4.2 最小生成树
*7.2.4 邻接多重表 )
7.3 图的遍历
连通树或无根树
无回路的图称为树或自由树 或无根树
2013-8-7
18
图的概念(8)
有向树:只有一个顶点的入度为0,其余 顶点的入度为1的有向图。
V1 V2
有向树是弱 连通的
V3
V4
2013-8-7
19
自测题
7. 下列关于无向连通图特性的叙述中,正确的是
2013-8-7
29
图的存贮结构:邻接矩阵
若顶点只是编号信息,边上信息只是有无(边),则 数组表示法可以简化为如下的邻接矩阵表示法: typedef int AdjMatrix[MAXNODE][MAXNODE];
*有n个顶点的图G=(V,{R})的邻接矩阵为n阶方阵A,其定 义如下:
1 A[i ][ j ] 0
【北方交通大学 2001 一.24 (2分)】
数据结构图的实验报告

数据结构图的实验报告数据结构图的实验报告引言:数据结构图是计算机科学中重要的概念之一。
它是一种用图形表示数据元素之间关系的数据结构,广泛应用于算法设计、程序开发和系统优化等领域。
本实验报告旨在介绍数据结构图的基本原理、实验过程和结果分析。
一、实验目的本次实验的主要目的是掌握数据结构图的基本概念和操作方法,以及通过实验验证其在解决实际问题中的有效性。
具体而言,我们将通过构建一个社交网络关系图,实现对用户关系的管理和分析。
二、实验方法1. 确定数据结构在本次实验中,我们选择了无向图作为数据结构图的基础。
无向图由顶点集和边集组成,每条边连接两个顶点,且没有方向性。
2. 数据输入为了模拟真实的社交网络,我们首先需要输入一组用户的基本信息,如姓名、年龄、性别等。
然后,根据用户之间的关系建立边,表示用户之间的交流和联系。
3. 数据操作基于构建好的数据结构图,我们可以进行多种操作,如添加用户、删除用户、查询用户关系等。
这些操作将通过图的遍历、搜索和排序等算法实现。
三、实验过程1. 数据输入我们首先创建一个空的无向图,并通过用户输入的方式逐步添加用户和用户关系。
例如,我们可以输入用户A和用户B的姓名、年龄和性别,并建立一条边连接这两个用户。
2. 数据操作在构建好数据结构图后,我们可以进行多种操作。
例如,我们可以通过深度优先搜索算法遍历整个图,查找与某个用户具有特定关系的用户。
我们也可以通过广度优先搜索算法计算某个用户的社交网络影响力,即与该用户直接或间接相连的其他用户数量。
3. 结果分析通过实验,我们可以观察到数据结构图在管理和分析用户关系方面的优势。
它能够快速地找到用户之间的关系,帮助我们了解用户的社交网络结构和影响力。
同时,数据结构图也为我们提供了一种可视化的方式来展示用户之间的关系,使得分析更加直观和易于理解。
四、实验结果通过实验,我们成功构建了一个社交网络关系图,并实现了多种数据操作。
我们可以根据用户的姓名、年龄和性别等信息进行查询,也可以根据用户之间的关系进行遍历和排序。
考研数据结构图的必背算法及知识点

考研数据结构图的必背算法及知识点Prepared on 22 November 20201.最小生成树:无向连通图的所有生成树中有一棵边的权值总和最小的生成树问题背景:假设要在n个城市之间建立通信联络网,则连通n个城市只需要n—1条线路。
这时,自然会考虑这样一个问题,如何在最节省经费的前提下建立这个通信网。
在每两个城市之间都可以设置一条线路,相应地都要付出一定的经济代价。
n个城市之间,最多可能设置n(n-1)/2条线路,那么,如何在这些可能的线路中选择n-1条,以使总的耗费最少呢分析问题(建立模型):可以用连通网来表示n个城市以及n个城市间可能设置的通信线路,其中网的顶点表示城市,边表示两城市之间的线路,赋于边的权值表示相应的代价。
对于n个顶点的连通网可以建立许多不同的生成树,每一棵生成树都可以是一个通信网。
即无向连通图的生成树不是唯一的。
连通图的一次遍历所经过的边的集合及图中所有顶点的集合就构成了该图的一棵生成树,对连通图的不同遍历,就可能得到不同的生成树。
图G5无向连通图的生成树为(a)、(b)和(c)图所示:G5G5的三棵生成树:可以证明,对于有n个顶点的无向连通图,无论其生成树的形态如何,所有生成树中都有且仅有n-1条边。
最小生成树的定义:如果无向连通图是一个网,那么,它的所有生成树中必有一棵边的权值总和最小的生成树,我们称这棵生成树为最小生成树,简称为最小生成树。
最小生成树的性质:假设N=(V,{E})是个连通网,U是顶点集合V的一个非空子集,若(u,v)是个一条具有最小权值(代价)的边,其中,则必存在一棵包含边(u,v)的最小生成树。
解决方案:两种常用的构造最小生成树的算法:普里姆(Prim)和克鲁斯卡尔(Kruskal)。
他们都利用了最小生成树的性质1.普里姆(Prim)算法:有线到点,适合边稠密。
时间复杂度O(N^2)假设G=(V,E)为连通图,其中V为网图中所有顶点的集合,E为网图中所有带权边的集合。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include<stdio.h>#include<stdlib.h>#include<malloc.h>#include<stack>#include <iostream>#include<iomanip>using namespace std;#define MAX_VERTEX_NUM 100#define INFINITY INT_MAX#define EXTERN 10#define OK 1#define ERROR -1#define MAX -1#define MAXW 10000typedef int Status;typedef bool VisitIf;typedef char VertexType;//顶点数据类型typedef int VRType; //顶点关系( 表示是否相邻) typedef int InfoType; //弧相关信息typedef enum{DG,DN,UDG,UDN} GraphKind;//图的类型bool visited[MAX_VERTEX_NUM];//邻接矩阵typedef struct ArcCell{VRType adj;//权值InfoType *info;}ArcCell,AdjMartix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; typedef struct{VertexType vexs[MAX_VERTEX_NUM]; //顶点向量AdjMartix arcs; //邻接矩阵int vexnum,arcnum; //图当前顶点数,弧数 GraphKind Kind; //图的类型}MGraph;bool VexExist(MGraph G,VertexType v)//判断定点是否在图中{int i;for(i=0;i<G.vexnum;i++)//遍历所有顶点if(G.vexs[i]==v)return true;return false;}Status CreatUDN(MGraph &G) //构造无向网{int i,j,w;char ch;VertexType v1,v2;Status LocateVex(MGraph G,VertexType v); //函数声明cout<<"输入顶点数,弧数:"<<endl;cin>>G.vexnum>>G.arcnum; //输入当前顶点数弧数是否有弧信息cout<<"输入顶点(字符型):"<<endl;for(i=0;i<G.vexnum;i++) //初始化邻接矩阵{for(j=0;j<G.vexnum;j++){G.arcs[i][j].adj=MAX;G.arcs[i][j].info=NULL;}}for(i=0;i<G.vexnum;i++) //顶点信息{cout<<"输入第"<<i+1<<"个顶点:";cin>>ch;if(VexExist(G,ch)) //判断是否存在 {cout<<"顶点输入有误!"<<endl;i--;}else G.vexs[i]=ch;}for(int k=0;k<G.arcnum;){cout<<"输入第"<<k+1<<"条弧:"<<endl;cin>>v1>>v2;cout<<"输入弧的权值:"<<endl;cin>>w;if((i=LocateVex(G,v1))!=-2)//if((j=LocateVex(G,v2))!=-2){G.arcs[i][j].adj=w;//对弧写入权值G.arcs[j][i].adj=w;//对称弧赋值k++;continue;};cout<<"顶点输入错误!";}return OK;}Status LocateVex(MGraph G,VertexType v) //若图中存在v,返回v在图中的位置{for(int i=0;i<G.vexnum;i++){if(v==G.vexs[i])return i;}return -2;}//对无向图求每个顶点的度,或对有向图求每个顶点的入度和出度(5分)Status GetDegree(MGraph G,VertexType v){int i=0;int degree=0;i=LocateVex(G,v);////若图中存在v,返回v在图中的位置if(i!=-2)//如果存在for(int j=0;j<G.vexnum;j++)if(G.arcs[i][j].adj>0) degree++;if(i==-2){cout<<"顶点输入有误!"<<endl;return ERROR;}return degree;}// 完成插入顶点和边(或弧)的功能(5分)Status InsertVex(MGraph &G,VertexType v) //图中插入顶点{int k=G.vexnum;if(G.vexnum<MAX_VERTEX_NUM){G.vexs[k]=v;G.vexnum++;for(int i=0;i<G.vexnum;i++){G.arcs[k][i].adj=MAX;G.arcs[k][i].info=NULL;G.arcs[i][k].adj=MAX;G.arcs[i][k].info=NULL;}cout<<"插入成功!"<<endl;}return ERROR;}Status InsertArc(MGraph &G,VertexType v1,VertexType v2) //图中插入弧{int w,i,j;i=LocateVex(G,v1);j=LocateVex(G,v2);if(i!=-2)if(j!=-2){cout<<"输入弧的权值:";cin>>w;G.arcs[i][j].adj=w;G.arcs[j][i]=G.arcs[i][j];return OK;}cout<<"输入有误,插入失败!";return ERROR;}//完成删除顶点和边(或弧)的功能(5分)Status DelVex(MGraph &G,VertexType v) //图中删除顶点{int i,j;i=LocateVex(G,v);if(i!=-2){for(j=0;j<G.vexnum-i-1;j++)G.vexs[i+j]=G.vexs[i+j+1]; //顶点的删除if(i<G.vexnum) //与顶点相关的弧的删除{for(j=0;j<G.vexnum-i-1;j++)for(int k=0;k<G.vexnum;k++){G.arcs[i+j][k].adj=G.arcs[i+j+1][k].adj;G.arcs[i+j][k].info=G.arcs[i+j+1][k].info;}for(j=0;j<G.vexnum-i-1;j++)for(int k=0;k<G.vexnum;k++){G.arcs[k][i+j].adj=G.arcs[k][i+j+1].adj;G.arcs[k][i+j].info=G.arcs[k][i+j+1].info;}G.vexnum--;return OK;}G.vexnum--;}return ERROR;}Status DelArc(MGraph &G,VertexType v1,VertexType v2) //删除弧{int i,j;i=LocateVex(G,v1);j=LocateVex(G,v2);if(i!=-2)if(j!=-2){G.arcs[i][j].adj=MAX;G.arcs[j][i].adj=MAX;G.arcs[i][j].info=NULL;G.arcs[j][i].info=NULL;cout<<"删除成功!";return OK;}return ERROR;}void ScanAll(MGraph G)//显示图的所有信息{int i;cout<<"图中顶点信息如下:"<<endl;for(i=0;i<G.vexnum;i++)cout<<G.vexs[i]<<" ";cout<<"邻接矩阵如下:"<<endl;cout<<setw(5)<<"矩阵:";for(i=0;i<G.vexnum;i++)cout<<setw(5)<<G.vexs[i];cout<<endl;for(i=0;i<G.vexnum;i++){cout<<setw(6)<<G.vexs[i];for(int j=0;j<G.vexnum;j++)cout<<setw(5)<<G.arcs[i][j].adj; cout<<endl;}}////////////////////////////////////////////////////////// ///////////////////////////////////////定义图的邻接多重表结构typedef struct Ebox{VisitIf mark; //访问标志int ivex,jvex;//该边依附的两个顶点位置int weight;struct Ebox *ilink,*jlink;//分别指向依附这两个顶点的下一条边InfoType info; //弧信息指针}Ebox;typedef struct VexBox//顶点定义{VertexType data;Ebox *firstedge;//指向第一条依附该顶点的边}VexBox;typedef struct//图定义{VexBox vexes[MAX_VERTEX_NUM];int vexnum,edgenum;//无向图的当前顶点数和边数}UdGraph;////////////////////////////////////////////////////////// //////////////////////////////////////以邻接多重表创建无向网Status CreatUdGraph(UdGraph &G){int i;int m,n,w;Ebox *p;VertexType v1,v2;Status UdGLocateVex(UdGraph &G,VertexType v);//声明cout<<"输入图顶点的个数和边的数目:"<<endl;cin>>G.vexnum>>G.edgenum;for(i=0;i<G.vexnum;i++) //顶点信息的输入{cout<<"输入第"<<i+1<<"顶点:";cin>>G.vexes[i].data;G.vexes[i].firstedge=NULL;}for(i=0;i<G.edgenum;i++) //边信息输入 {cout<<"共"<<G.edgenum<<"条边"<<"输入第"<<i+1<<"条边:";cin>>v1>>v2;cout<<"输入权值:";cin>>w;if((m=UdGLocateVex(G,v1))!=-2)if((n=UdGLocateVex(G,v2))!=-2){p=(Ebox*)malloc(sizeof(Ebox));if(!p) return ERROR;p->ivex=m;p->jvex=n;p->weight=w;p->ilink=G.vexes[m].firstedge; //插入顶点m表头G.vexes[m].firstedge=p;p->jlink=G.vexes[n].firstedge; //插入顶点n的表头G.vexes[n].firstedge=p;};}return OK;}Status UdGLocateVex(UdGraph &G, VertexType v) //返回v在图G中的位置{for(int i=0;i<G.vexnum;i++){if(v==G.vexes[i].data)return i;}return -2;}Status UdGInsertVex(UdGraph &G) //插入顶点{if(G.vexnum<MAX_VERTEX_NUM){cout<<"输入要插入的顶点的信息:";cin>>G.vexes[G.vexnum].data;G.vexnum++;G.vexes[G.vexnum-1].firstedge=NULL;return OK;}return ERROR;}Status UdGInsertEadge(UdGraph &G,VertexType v1,VertexType v2,int w) //插入边{int m,n;m=UdGLocateVex(G,v1);n=UdGLocateVex(G,v2);Ebox *p;if(m!=-2)//如果点v1存在,并返回值给mif(n!=-2){p=(Ebox*)malloc(sizeof(Ebox));//申请一个结点if(!p) return ERROR;p->ivex=m;p->jvex=n;p->weight=w;p->ilink=G.vexes[m].firstedge; //插入顶点m表头G.vexes[m].firstedge=p;p->jlink=G.vexes[n].firstedge; //插入顶点n的表头G.vexes[n].firstedge=p;return OK;};cout<<"边信息输入有误!";return ERROR;}Status UdGGetDegree(UdGraph G,VertexType v) //返回v的度数{int degree=0;int i;Ebox *p;if((i=UdGLocateVex(G,v))==-2){cout<<"输入的顶点信息有误!";return ERROR;}p=G.vexes[i].firstedge;while(p){degree++;if(p->ivex==i) p=p->ilink;else p=p->jlink;}return degree;}Status UdGFirstVex(UdGraph G,int i) //返回v的第一个邻接点{if(i>G.vexnum||i<0){cout<<"输入的顶点有误!";return ERROR;}if(G.vexes[i].firstedge==NULL) return -2; //没有邻接点if(G.vexes[i].firstedge->ivex==i) return G.vexes[i].firstedge->jvex; //返回邻接点else return G.vexes[i].firstedge->ivex;}//返回i相对于j的下一个邻接点Status UdGNextVex(UdGraph G,int i,int j){Ebox *p;if(i>G.vexnum||i<0||j>G.vexnum||j<0){cout<<"输入的两个顶点有误!";return ERROR;}p=G.vexes[i].firstedge;while(p){if(p->ivex==j){p=p->jlink;break;}if(p->jvex==j){p=p->ilink;break;}if(p->ivex==i) p=p->ilink;else p=p->jlink;}if(!p) return -2; //没有邻接点 if(p->ivex==i) return p->jvex;else return p->ivex;}//邻接多重表转换为邻接矩阵MGraph StructTransform(UdGraph G1){int i,j;MGraph G;Ebox *p;G.vexnum=G1.vexnum;for(i=0;i<G1.vexnum;i++){G.vexs[i]=G1.vexes[i].data; //复制顶点数组}for(i=0;i<G.vexnum;i++) //初始化邻接矩阵for(j=0;j<G.vexnum;j++)G.arcs[i][j].adj=MAX;for(i=0;i<G1.vexnum;i++)visited[i]=false; //访问标记初始化for(i=0;i<G1.vexnum;i++) //邻接矩阵赋值{p=G1.vexes[i].firstedge;while(p){G.arcs[p->ivex][p->jvex].adj=G.arcs[p->jvex][p->ivex].adj= p->weight;if(p->ivex==i) p=p->ilink;else p=p->jlink;}}return G;}//邻接矩阵转换为邻接多重表UdGraph StructTransform(MGraph G1){int i,j;UdGraph G;//顶点数组的复制G.vexnum=G1.vexnum;for(i=0;i<G1.vexnum;i++)G.vexes[i].data=G1.vexs[i];for(i=0;i<G.vexnum;i++) G.vexes[i].firstedge=NULL;//根据邻接矩阵构造边for(i=0;i<G.vexnum;i++)for(j=i+1;j<G.vexnum;j++)if(G1.arcs[i][j].adj>0)UdGInsertEadge(G,G.vexes[i].data,G.vexes[j].data,G1.arcs[i ][j].adj);return G;}/********二叉树*******/typedef struct CSNode{VertexType v;CSNode *lchild;CSNode *nextsibling;} CSNode,*CSTree;//输出图的深度优先遍历序列或广度优先遍历序列(5分)Status DFSTraverse(UdGraph G) //返回连通分量{int i;int count=0;void DFS(UdGraph G,int i);for(i=0;i<G.vexnum;i++)visited[i]=false; //访问标志初始化 cout<<"深度优先遍历结果:"<<endl;for(i=0;i<G.vexnum;i++){if(!visited[i]){count++; //连通分量计数器 DFS(G,i);}}cout<<endl;return count;}void DFS(UdGraph G,int i){int w;visited[i]=true;cout<<G.vexes[i].data;for(w=UdGFirstVex(G,i);w!=-2;w=UdGNextVex(G,i,w)) if(!visited[w]) DFS(G,w);}Status ScanUdGraph(UdGraph G)//输出无向网{int i;Ebox *p;cout<<"图中顶点信息:"<<endl;for(i=0;i<G.vexnum;i++)cout<<"编号"<<i<<"\t"<<G.vexes[i].data<<endl;for(i=0;i<G.vexnum;i++){p=G.vexes[i].firstedge;if(!p){cout<<"没有与该顶点相关的边";continue;}cout<<"与顶点"<<G.vexes[i].data<<"相连的边:"<<endl;while(p){cout<<p->ivex<<"-"<<p->jvex<<" 权值:"<<p->weight<<endl;if(p->ivex==i) p=p->ilink;else p=p->jlink;}}return OK;}//求图的深度优先或广度优先的生成树(或生成森林)(存储结构为孩子-兄弟链表),并对生成树进行遍历(15分)//深度优先遍历生成树void DFSForest(UdGraph G,CSTree &T){int v;T=NULL;CSTree p=NULL;CSTree q=NULL;void DFSTreeSet(UdGraph G,int v,CSTree &T);for(v=0;v<G.vexnum;++v)visited[v]=false;for(v=0;v<G.vexnum;++v)if(!visited[v]){p=(CSTree)malloc(sizeof(CSNode)); if(!p){cout<<"内存分配失败";return;}p->v=G.vexes[v].data;p->lchild=p->nextsibling=NULL;if(!T) T=p;else q->nextsibling=p;q=p;DFSTreeSet(G,v,p);}}void DFSTreeSet(UdGraph G,int v,CSTree &T) {int w;bool first;visited[v]=true;first=true;CSTree p,q=T->lchild;for(w=UdGFirstVex(G,v);w!=-2;w=UdGNextVex(G,v,w)) if(!visited[w]){p=(CSTree)malloc(sizeof(CSNode));if(!p){cout<<"内存分配失败!";return;}p->v=G.vexes[w].data;p->lchild=p->nextsibling=NULL;if(first){T->lchild=p;first=false;}else{q->nextsibling=p;}q=p;DFSTreeSet(G,w,q);}}//深度优先遍历孩子兄弟链表Status DFSTree(CSTree T){if(!T) return OK;cout<<T->v<<" ";if(T->lchild) DFSTree(T->lchild);if(T->nextsibling) DFSTree(T->nextsibling); return OK;}//判断图中有没有环bool UdGLoopJudge(UdGraph G){int VD[ MAX_VERTEX_NUM];bool flag=false; //数组中点空标志int i,j,m;int count; //记录数组中为-1的数目Ebox *p;//VexDegree VD[MAX_VEX_NUM];for(i=0;i<G.vexnum;i++) //保存顶点的度数VD[i]=UdGGetDegree(G,G.vexes[i].data);while(!flag){count=1;for(j=0;j<G.vexnum;j++) //遍历数组检测度数为的点 {if(VD[j]==1){VD[j]=-1;m=j;break;}if(VD[j]==-1) count++;if(j==G.vexnum-1)m=-1;}//cout<<"-1点:"<<count<<endl;if(m==-1){if(count==G.vexnum) break;flag=true;break;}p=G.vexes[m].firstedge;while(p){if(p->ivex==m){if(VD[p->jvex]<0) p=p->ilink; else{VD[p->jvex]--;p=p->ilink;}}else{if(VD[p->ivex]<0) p=p->jlink; else{VD[p->ivex]--;p=p->jlink;}}}}return flag;}//普利姆算法求最小生成树void MiniSpanTree(MGraph G,VertexType u) {int k;int j,i;int count=0,min;struct{VertexType adjvex;int lowcost;}closedge[ MAX_VERTEX_NUM];k=LocateVex(G,u);for(j=0;j<G.vexnum;j++)if(j!=k){closedge[j].adjvex=u;closedge[j].lowcost=G.arcs[k][j].adj;};closedge[k].lowcost=0;count=1;cout<<"最小生成树的各个边信息如下:"<<endl;while(count!=G.vexnum){min=1000;for(i=0;i<G.vexnum;i++){if(closedge[i].lowcost==MAX||closedge[i].lowcost==0) continue;if(closedge[i].lowcost<min){min=closedge[i].lowcost;k=i;}}//cout<<"花费最小边对应点:"<<G.vexs[k]<<endl;// 求出加入生成树的下一个顶点(k)cout<<closedge[k].adjvex<<"-"<<G.vexs[k]<<":"<<closedge[k] .lowcost<<endl;// 输出生成树上一条边closedge[k].lowcost = 0; // 第k顶点并入U集count++;for (i=0; i<G.vexnum; ++i)//修改其它顶点的最小边{if(closedge[i].lowcost==-1){closedge[i].adjvex = G.vexs[k];closedge[i].lowcost = G.arcs[k][i].adj; continue;}if(closedge[i].lowcost==0) continue;if (G.arcs[k][i].adj ==-1 ) continue;if(G.arcs[k][i].adj<closedge[i].lowcost){closedge[i].adjvex = G.vexs[k];closedge[i].lowcost = G.arcs[k][i].adj; continue;}}}}//10、求顶点u到v的一条简单路径(10分)//m到n的简单路径char path[100];int count1=0;int flag=false;int easy_way(UdGraph G,int m,int n){int i;int DFSway(UdGraph g,int m,int n);for(i=0;i<100;i++) //路径设为空path[i]=' ';count1=0;flag=false;for(i=0;i<G.vexnum;i++) //访问标志数组初始化visited[i]=false;DFSway(G,m,n);if(!flag) return -1;for(i=0;i<count1;i++){if(path[i]==G.vexes[n].data) break;cout<<path[i];}cout<<G.vexes[n].data;return 0;}int DFSway(UdGraph g,int m,int n){//从第m个顶点出发递归地深度优先遍历图Gint w;int i=1;visited[m]=true;path[count1]=g.vexes[m].data;for(w=UdGFirstVex(g,m);w>=0;w=UdGNextVex(g,m,w)){if(!visited[w]){i++;if(w==n)flag=true;count1++;if(!flag){DFSway(g,w,n);//对未被访问的邻接顶点w递归调用DFS}}}if(!flag){if(i==UdGGetDegree(g,g.vexes[m].data))path[count1]=' ';count1--;}return flag;}//求两点的简单路径void print_easy_way(UdGraph G){char ch1,ch2;int i,j;cout<<"输入需要求简单路径的两个顶点:"<<endl; cin>>ch1>>ch2;i=UdGLocateVex(G,ch1);j=UdGLocateVex(G,ch2);cout<<"简单路径为:";if(easy_way(G,i,j)==-1)cout<<"不存在路径";cout<<endl;}//堆栈的基本操作typedef char SElemType;#define STACK_INIT_SIZE 100#define STACKINCREMENT 10typedef struct {int *base; //栈底指针int *top; //栈顶指针int stacksize; //栈的大小} SqStack;int InitStack (SqStack &S){S.base=(int *)malloc(STACK_INIT_SIZE * sizeof(int)); if (!S.base)return(0);S.stacksize = STACK_INIT_SIZE ;S.top = S.base;return(1);}bool StackEmpty (SqStack S){if(S.base==S.top)return(true);//栈空的条件return(false);}int Pop(SqStack &S, int &e){if(S.base==S.top)return(0);//栈空//e=*--S.top;S.top--;e=*S.top;return(1);}int Push(SqStack &S, int e){if(S.top-S.base>= S.stacksize) {//栈满,申请存储空间S.base=(int*)realloc(S.base,(S.stacksize+STACKINCREMENT) * sizeof(int));if (!S.base)return (0);S.stacksize += STACKINCREMENT ;}*S.top=e ;S.top++;return(1);}//求顶点u到其余各点的最短路径int prev[MAXW];//prev[v]表示从源s到顶点v的最短路径上顶点的前驱顶点。